【C/C++学院】(8)全局函数和类成员函数转化/友元/操作符重载

简介: <h1><span style="font-family:'Microsoft YaHei UI','Microsoft YaHei',SimSun,'Segoe UI',Tahoma,Helvetica,sans-serif,'Microsoft YaHei',Georgia,Helvetica,Arial,sans-serif,宋体,PMingLiU,serif; font-size:

1.全局函数和类成员函数转化

    全局函数和成员函数的相互转化:只需要修改一个指向本类的this指针;

#include <iostream>
using namespace std;

class Test
{
public:
	Test(int a, int b)
	{
		this->a = a;
		this->b = b;
	}
	//成员函数
	Test &Gadd2(Test &t2)
	{
		this->a = this->a + t2.a;
		this->b = this->b + t2.b;
		return *this;
	}
public:
	int a;
	int b;
};
//全局函数
Test &Gadd1(Test &t1, Test &t2)
{
	Test t3(0, 0);
	t3.a = t1.a + t2.a;
	t3.b = t1.b + t2.b;
	return t3;
}

//从成员函数转化为全局函数 只需要加一个 this指针(指向本类的类指针)
//从全局函数转化为类的成员函数是,需要减一个做左操作数参数
void main()
{
	Test t1(1, 2), t2(3, 4);
	//Test t3 = Gadd1(t1, t2);
	t1.Gadd2(t2);

	system("pause");
}

2.友元

2.1友元函数

#include "iostream"
using namespace std;
class Test2
{
public:
    //友元函数的特点是:有一个参数是友元类的指针或引用
    friend int OpMem(Test2 *p, int a); //友元函数
    Test2(int a, int b)
    {
        this->a = a;
        this->b = b;
    }
    int getA()
    {
        return this->a;
    }
protected:
private:
    int a;
    int b;
};
int OpMem(Test2 *p, int a)
{
    p->a = a;
    return 0;
}
void main()
{
    Test2 t1(1, 2);
    t1.getA();//没有friend的情况下,如果获取对象t1的私有数据,需要用get方法。
    OpMem(&t1, 10);
    system("pause");
}

2.2友元类

#include <iostream>
using namespace std;

class A
{
	friend class B;//B是A的友元类
public:
	void  Display() { cout << x << endl; };
private:
	int  x;
};
//设计模式中的组合场景。表象是设置b100, 本质上是修改a的数据。
class  B
{
public:
	void Set(int i) { Aobject.x = i; }
	void Display()  { Aobject.Display(); }
private:
	A  Aobject;
};

void main()
{
	B  Bobject;
	Bobject.Set(100);
	Bobject.Display();
	system("pause");
}


3.操作符重载

C++有许多内置的数据类型,包括int,char,double等,每一种类型都有许多运算符,例如加,减,乘,除等。当用户定义了类的对象时,两个对象之间是不能进行这些操作的,比如hyong类的对象a+b,这样的语句如果没有重载+运算符就会出错。但C++允许用户把这些运算符添加到自已的类中以方便类对象之间的运算就像内置类型的运算一样方便,比如对象a+b这样就很明白更容易懂,当然也可以在类中定义一个对象间相加的函数,比如a.add(b)调用函数add()以实现两个对象a和b相加,但是这条语句没有比a+b更容易让人理解。

3.1通过友元函数实现操作符重载,

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现+操作
    friend Fushu operator+(Fushu &c1, Fushu &c2);
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
};
Fushu operator+(Fushu &c1, Fushu &c2)
{
    Fushu tmp;
    tmp.a = c1.a + c2.a;
    tmp.b = c1.b + c2.b;
    return tmp;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    Fushu c3 = c1+c2;
    c3.print();
    system("pause");
}

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现前++操作
    friend Fushu &operator++(Fushu &c2);
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
};
Fushu &operator++(Fushu &c2)
{
    c2.a++;
    c2.b++;
    return c2;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    ++c2;
    
    c2.print();
    
    system("pause");
}

3.2通过类的成员函数实现操作符重载

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现+操作
    friend Fushu operator+(Fushu &c1, Fushu &c2);
public:
    //通过类的成员函数实现-操作
    Fushu operator-(Fushu &c2)
    {
        Fushu tmp;
        tmp.a = this->a - c2.a;
        tmp.b = b - c2.b;//此处的this可以省略
        return tmp;
    }
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
};
Fushu operator+(Fushu &c1, Fushu &c2)
{
    Fushu tmp;
    tmp.a = c1.a + c2.a;
    tmp.b = c1.b + c2.b;
    return tmp;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    Fushu c3 = c1+c2;//operator+(c1,c2);
    c3.print();
//目标 通过类的成员函数,完成操作符重载
//1 要承认操作符重载是一个函数,要写函数原型
//2 写出函数调用语言 c1.operator-(c2)
//3 完善函数原型   
    Fushu c4 = c1 - c2;//operator-(c1,c2) -->c1.operator-(c2)-->Fushu operator-(Fushu &c2);
    c4.print();
    system("pause");
}

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现前++操作
    friend Fushu &operator++(Fushu &c2);
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
public://通过类的成员函数实现前--操作
    Fushu& operator--()
    {
        this->a--;
        this->b--;
        return *this;
    }
};
Fushu &operator++(Fushu &c2)
{
    c2.a++;
    c2.b++;
    return c2;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    //通过友元函数实现前++操作
    ++c2;    
    c2.print();
    //通过类的成员函数实现前--操作
    --c2;    
    c2.print();
    system("pause");
}

综合:

#include <iostream>
using namespace std;

class Fushu
{
private:
	int a;
	int b;
	//通过友元函数实现前++操作
	friend Fushu &operator++(Fushu &c2);
	//通过友元函数实现后++操作
	friend Fushu operator++(Fushu &c2, int);//用缺省参数占位,跟前++区分
public:
	Fushu(int a=0, int b=0)
	{
		this->a = a;
		this->b = b;
	}
	void print()
	{
		cout << a << "+" << b << "i" << endl;
	}
public:
	//通过类的成员函数实现前--操作
	Fushu& operator--()
	{
		this->a--;
		this->b--;
		return *this;
	}
	//通过类的成员函数实现前--操作
	Fushu& operator--(int)//用缺省参数占位,跟后--区分
	{
		Fushu tmp;
		tmp = *this;
		this->a--;
		this->b--;
		return tmp;
	}
};

Fushu &operator++(Fushu &c2)
{
	c2.a++;
	c2.b++;
	return c2;
}

Fushu operator++(Fushu &c2, int)
{
	Fushu tmp;
	tmp = c2;
	c2.a++;
	c2.b++;
	return tmp;
}

void main()
{
	Fushu c1(1, 2), c2(3, 4);
	//通过友元函数实现前++操作
	++c2;	
	c2.print();
	//通过类的成员函数实现前--操作
	--c2;	
	c2.print();
	//通过友元函数实现后++操作
	c2++;
	c2.print();
	//通过类的成员函数实现后--操作
	c2--;
	c2.print();

	system("pause");
}


3.3操作符重载的正规写法

      通过友元函数可以获取友元类的私有属性,相当于获取了程序的一个后门。
#include <iostream>
using namespace std;

class Fushu
{
private:
	int a;
	int b;
	friend ostream& operator<<(ostream &cout, Fushu &c);
public:
	Fushu(int a=0, int b=0)
	{
		this->a = a;
		this->b = b;
	}
	void print()
	{
		cout << a << "+" << b << "i" << endl;
	}
public:
	//通过类的成员函数实现前++操作
	Fushu &operator++()
	{
		this->a++;
		this->b++;
		return *this;
	}
	//通过类的成员函数实现前--操作
	Fushu& operator--()
	{
		this->a--;
		this->b--;
		return *this;
	}
	//通过类的成员函数实现后--操作
	Fushu operator--(int)//用缺省参数占位,跟后--区分
	{
		Fushu tmp;
		tmp = *this;
		this->a--;
		this->b--;
		return tmp;
	}
	//通过类的成员函数实现后++操作
	Fushu operator++(int)//用缺省参数占位,跟后--区分
	{
		Fushu tmp;
		tmp = *this;
		this->a++;
		this->b++;
		return tmp;
	}
};

ostream& operator<<(ostream &co, Fushu &c)
{
	cout << "我是复数:" << endl;
	cout << c.a << "+" << c.b << "i" << endl;
	return co;
}

void main()
{
	Fushu c1(1, 2), c2(3, 4);
	++c2;	
	c2.print();

	--c2;	
	c2.print();

	c2++;
	c2.print();

	c2--;
	c2.print();

	cout << 1 << endl;
	cout << "hello" << endl;
	//函数返回值当左值的时候,需要返回一个对象的引用, 实现链式编程
	cout << c2 << "连续" << endl;
	//没有方法去在cout类里面添加函数operator<<,只能通过全局函数实现。
	//cout.operator<<( c1);
	//void operator<<(ostream &out, Complex &c1)

	system("pause");
}

3.4操作符重载在项目中的应用:

基本的数组框架
Array.h
//Array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_

class Array
{
private:
	int mLength;//数组的长度
	int* mSpace;//内存空间

public:
	Array(int length);
	Array(const Array& obj);//copy构造函数
	int length();//取得数组长度
	void setData(int index, int value);
	int getData(int index);
	~Array();
};

#endif
Array.cpp
//Array.cpp
#include "Array.h"

Array::Array(int length)
{
	if (length < 0)
	{
		length = 0;
	}
	mLength = length;
	mSpace = new int[mLength];
}
Array::Array(const Array& obj)
{
	mLength = obj.mLength;
	mSpace = new int[mLength];
	for (int i = 0; i<mLength; i++)
	{
		mSpace[i] = obj.mSpace[i];
	}
}
int Array::length()
{
	return mLength;
}
void Array::setData(int index, int value)
{
	mSpace[index] = value;
}
int Array::getData(int index)
{
	return mSpace[index];
}
Array::~Array()
{
	mLength = -1;
	delete[] mSpace;
}
//ArrayTest.cpp
//ArrayTest.cpp
#include "Array.h"
#include <iostream>
using namespace std;

int main()
{
	Array a1(10);

	for (int i = 0; i<a1.length(); i++)
	{
		a1.setData(i, i);  //a[i] = 1;
	}

	for (int i = 0; i<a1.length(); i++)
	{
		printf("array %d: %d\n", i, a1.getData(i));
		// printf("array %d: %d\n", i, a1[i]));
	}

	Array a2 = a1;
	for (int i = 0; i<a2.length(); i++)
	{
		printf("array %d: %d\n", i, a2.getData(i));
	}
	system("pause");
	return 0;
}

重载[]  =  ==  !=操作符后的代码:
//Array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_
#include <string.h>
class Array
{
private:
	int mLength;//数组的长度
	int* mSpace;//内存空间

public:
	Array(int length);
	Array(const Array& obj);//copy构造函数
	int length();//取得数组长度
	void setData(int index, int value);
	int getData(int index);
	~Array();
public:
	int & operator[](int i);
	void operator=(Array &a2);
	bool operator==(Array &a1);
	bool operator!=(Array &a1);
};

#endif

//Array.cpp
#include "Array.h"

Array::Array(int length)
{
	if (length < 0)
	{
		length = 0;
	}
	mLength = length;
	mSpace = new int[mLength];
}
Array::Array(const Array& obj)
{
	mLength = obj.mLength;
	mSpace = new int[mLength];
	for (int i = 0; i<mLength; i++)
	{
		mSpace[i] = obj.mSpace[i];
	}
}
int Array::length()
{
	return mLength;
}
void Array::setData(int index, int value)
{
	mSpace[index] = value;
}
int Array::getData(int index)
{
	return mSpace[index];
}
Array::~Array()
{
	mLength = -1;
	delete[] mSpace;
}

int& Array::operator[](int i)
{
	return this->mSpace[i];
}

void Array::operator = (Array &a2)
{
	if (this->mSpace != NULL)
	{
		delete[] mSpace;
	}	
	mLength = a2.mLength;
	mSpace = new int[mLength];
    memcpy(mSpace, a2.mSpace, mLength);
}

bool Array::operator==(Array &a1)
{
	//先比较长度
	if (mLength != a1.mLength)
	{
		return false;
	}
	//比较内容
	for (int i = 0; i < a1.mLength; i++)
	{
		if (a1[i] != mSpace[i])
		{
			return false;
		}
	}
	return true;
}
//利用相等判断不等 
bool Array::operator!=(Array &a1)
{
	return !(a1 == *this);
}

//ArrayTest.cpp
#include "Array.h"
#include <iostream>
using namespace std;

int main()
{
	Array a1(10);

	for (int i = 0; i<a1.length(); i++)
	{
		//a1.setData(i, i);  
		a1[i] = i;
	}
	
	for (int i = 0; i<a1.length(); i++)
	{
		//printf("array %d: %d\n", i, a1.getData(i));
		printf("array %d: %d\n", i, a1[i]);
	}

	Array a2 = a1;
	for (int i = 0; i<a2.length(); i++)
	{
		//printf("array %d: %d\n", i, a2.getData(i));
		printf("array %d: %d\n", i, a1[i]);
	}

	Array a3(10);
	a3 = a2; //执行=操作
	
	if (a2 == a1)
	{
		printf("相等");
	}
	else
	{
		printf("不相等");
	}
	system("pause");
	return 0;
}







目录
相关文章
|
1月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
43 0
|
1月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
111 0
|
3月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
113 12
|
5月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
4月前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
98 16
|
4月前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
|
4月前
|
存储 编译器 C++
类和对象(上)(C++)
本篇内容主要讲解了C++中类的相关知识,包括类的定义、实例化及this指针的作用。详细说明了类的定义格式、成员函数默认为inline、访问限定符(public、protected、private)的使用规则,以及class与struct的区别。同时分析了类实例化的概念,对象大小的计算规则和内存对齐原则。最后介绍了this指针的工作机制,解释了成员函数如何通过隐含的this指针区分不同对象的数据。这些知识点帮助我们更好地理解C++中类的封装性和对象的实现原理。
|
5月前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
4月前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
235 6
|
4月前
|
编译器 C++
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!