4.5运算符重载 加号运算符+ 左移运算符<< 递增运算符++

4.5 运算符重载

4.5运算符重载 加号运算符+ 左移运算符<< 递增运算符++_第1张图片

所谓两个自定义数据相加,即两个结构体,或者两个对象相加。等操作。

#include
using namespace std;

class Person
{
     
public:
	int m_A;
	int m_B;
	//1、通过成员函数重载加号运算符
	//Person PersonAddPerson(Person& p)
	//{
     
	//	Person temp;
	//	temp.m_A = this->m_A + p.m_A;
	//	temp.m_B = this->m_B + p.m_B;
	//	return temp;
	//}
	//Person operator+(Person& p)
	//{
     
	//	Person temp;
	//	temp.m_A = this->m_A + p.m_A;
	//	temp.m_B = this->m_B + p.m_B;
	//	return temp;
	//}
};
//2、通过全局函数重载+号运算符。
Person operator+(Person& p1, Person& p2)
{
     
	Person temp;
	temp.m_A = p1.m_A + p2.m_A;
	temp.m_B = p1.m_B + p2.m_B;
	return temp;
}
//3、在运算符重载的过程中,也可以发生函数重载
Person operator+(Person& p1, int a)
{
     
	Person temp;
	temp.m_A = p1.m_A + a/5;
	temp.m_B = p1.m_B + a/2;
	return temp;
}
void test()
{
     
	Person p1;
	Person p2;
	p1.m_A = 10;
	p1.m_B = 10;
	p2.m_A = 10;
	p2.m_B = 10;
	//Person p3 = p1.operator+(p2);//这种写法可以简化为以下:
	//通过成员函数重载了加号。
	Person p3 = p1 + p2;//当你使用这种编译器指定的函数名称之后就可以这么写。
	cout << "p3: " << p3.m_A << "  " << p3.m_B << endl;//Person + Person ;
	//同样的,通过全局函数重载+号本质是:
	//Person p3 = operator + (p1, p2);//可以简化为:
	//Person p3 = p1 + p2;

	//3、在运算符重载的过程中,也可以发生函数重载
	//例如想实现代码Person p4 = p1 + 10;
	Person p4 = p1 + 10;//Person + int
	cout << "p4: " << p4.m_A << "  " << p4.m_B << endl;
}

int main()
{
     

	test();
	system("pause");
	return 0;
}

注意事项:

在加号运算符重载的程序中,需要注意的是,要先有重载函数,然后再有简化版的对象相加的代码。否则,编译器依然不知道要怎么相加。

在这里,有两种重载方式:1、通过成员函数重载;2、通过全局函数重载。

1、通过成员函数重载

Person p3 = p1.operator+(p2);

简化为

Person p3 = p1 + p2;

2、通过全局函数重载

Person p3 = operator + (p1, p2);

简化为

Person p3 = p1 + p2;

3、在运算符重载的过程中,也可以发生函数重载

根据函数的参数类型不同,发生函数重载。

在这里插入图片描述
4.5运算符重载 加号运算符+ 左移运算符<< 递增运算符++_第2张图片
问题1:为什么类,对象,在做函数参数的时候,总是以引用的方式?
为了实现代码Person p;cout<

#include
using namespace std;
class Person
{
     
public:
	Person(int a, int b)
	{
     
		m_A = a;
		m_B = b;
	}
	friend ostream& operator<<(ostream& cout, Person& p);
private:
	int m_A;
	int m_B;
	//利用成员函数重载左移运算符 p.operator<<(cout) 简化版本:p<
	//因此不会利用成员函数来重载左移运算符,因为无法实现cout在左侧。
	/*void operator<<(cout)
	{
		
	}*/
};
//因此只能使用全局函数重载左移运算符
//cout的数据类型是ostream,输出流。
ostream & operator<<(ostream &cout,Person &p)//本质 operator<<(cout,p) 简化为 cout << p
{
     
	cout << "m_A = " << p.m_A << endl << "m_B = " << p.m_B << endl;
	return cout;
}
void test()
{
     
	Person p(10,10);
	//cout << p.m_A << endl << p.m_B << endl;
	cout << p<<"Hello World"<<endl;//cout,标准输出流对象,由ostream类创建。
	//上一行的<<是经过重载了的,而上上一行的<<未经过重载,
	//在这里实际上,使用了链式编程的思想,即将<<看作是一个函数,输入参数ostream cout和Person p
	//每运算一次,返回一个cout,作为下一个<<函数的输入参数,同时右边有新的参数输入。
}

int main()
{
     
	test();
	system("pause");
	return 0;
}

知识点梳理:

1、为了想实现代码cout <

2、左移运算符的重载不可以使用成员函数书写,只能用全局函数,cout在左侧,p在右侧;cout的数据类型是ostream,输出流,并使用引用的方式作为重载函数的参数,目的是为了保证全局只有一个它。

ostream & operator<<(ostream &cout,Person &p)//本质 operator<<(cout,p) 简化为 cout << p
{
     
	cout << "m_A = " << p.m_A << endl << "m_B = " << p.m_B << endl;
	return cout;
}

3、如果成员属性是私有的,可以使用友元,来访问。

friend ostream& operator<<(ostream& cout, Person& p);

在这里插入图片描述
4.5运算符重载 加号运算符+ 左移运算符<< 递增运算符++_第3张图片
4.5.3 递增运算符++重载
利用递增运算符++,自己写一个整形变形。自己写一个,模拟一个整形变量。
4.5运算符重载 加号运算符+ 左移运算符<< 递增运算符++_第4张图片
回顾一下递增

//前置递增
int a = 10;
cout << + + a << endl;//11 前置递增,先让此变量递增,再输出结果。
cout << a << endl;// 11
//后置递增
int b = 10;
cout << b + +  << endl;//10 后置递增,先输出结果,再让此变量递增。
cout << b << endl;// 11

为了实现以下代码,需将递增运算符++进行重载

class MyInteger
{
     
public:
	MyInteger() {
     m_Num = 0;}//构造函数,初始化
private:
	int m_Num;
};
void test01()
{
     
	MyInteger myint;
	cout<<  + + myint<<endl;//对象的前++
	cout<< myint + + <<endl;//对象的后++
}

因此,要重载运算符++

#include
using namespace std;
#include

class MyInteger
{
     
	friend ostream & operator<<(ostream& cout, MyInteger myint);
public :
	MyInteger() 
	{
     
		m_Num = 0;
	}
	//利用成员函数重载前置++
	MyInteger &operator++() //在这里为什么要用引用的方式做返回?为什么要加&
	{
     						//返回引用是为了一直对一个数据进行递增操作。若无&,则会返回一个新的对象,再对新的对象进行递增。
		m_Num ++ ; //前++ 是先计算,再赋值
		return *this;
	}
	//利用成员函数重载后置++
	MyInteger  operator++(int) //在这里,返回值,而非返回引用。因为在此处
	//返回的并非执行对象的本身,而是返回了一个临时创建的对象。
	//int表占位参数,可用于区分前置和后置递增,且在这只能用int,用double float不好使。temp是一个局部对象,在函数执行完后被释放,再对该对象操作就是非法操作了。
	{
     						
		//先 记录结果
		MyInteger temp = *this;
		//后 递增
		m_Num++;
		//最后 将记录的结果做返回
		return temp;
	}
private:
	int m_Num;
};

ostream& operator<<(ostream &cout,MyInteger myint) //重载左移运算符<<
{
     
	cout << myint.m_Num ;
	return cout;
}

void test01()
{
     
	MyInteger myint;
	cout << myint << endl;
	cout << ++(++myint) << endl;
}

void test02()
{
     
	MyInteger myint2;
	cout << myint2++ << endl;
	cout << myint2 << endl;
}

int main()
{
     
	test02();
	system("pause");
	return 0;
}

知识点1:为什么在前++的重载函数程序中,返回的是引用而不能是对象的值?

	//利用成员函数重载前置++
	MyInteger &operator++() //在这里为什么要用引用的方式做返回?为什么要加&
	{
     						//返回引用是为了一直对一个数据进行递增操作。若无&,则会返回一个新的对象,再对新的对象进行递增。
		m_Num ++ ;
		return *this;
	}

对于系统整形int,有:

	MyInteger myint;
	cout << ++(++myint) << endl; // 2
	cout << myint << endl;// 重载函数加&时输出2,不加&时输出1

没有&时,在第一个++执行完后,重载函数返回的是另外一个对象,其m_Num是1,然后再++的结果是2是没问题,但是问题在于,原对象myint的m_Num依然是1,不是2。而加上&后,每次++操作的对象都是myint。

	int a = 0;
	cout << ++(++a) << endl;// 2
	cout << a << endl;// 2

而对于自定义整形MyInteger
在本课程中,有一个疑惑点:

  • 即,在本案例中,重载递增运算符++中,使用的重载左移运算符<<的程序与上一节的案例中的程序不同。

即第二个对象参数是否以引用方式传入。本节中没有&,

ostream& operator<<(ostream &cout,MyInteger myint) 
{
     
	cout << myint.m_Num ;
	return cout;
}

上一节左移运算符<<的重载函数中有&

ostream & operator<<(ostream &cout,Person &p)//本质 operator<<(cout,p) 简化为 cout << p
{
     
	cout << "m_A = " << p.m_A << endl << "m_B = " << p.m_B << endl;
	return cout;
}

当在<<的重载程序函数中,以引用方式来引入对象作为函数参数,在后置递增的执行程序中会报错:
对于这个问题的解释是:
在后++的重载函数中,返回的是一个数值,并非引用形式,故,在重载后的左移运算符<<中,myint ++返回的是一个对象数值,而非引用。所以,在这里,应该用非引用的形式。
可是还有一点,在前置++的重载函数中,是以引用形式返回该对象本身,即 ++myint以引用形式返回自己。那在重载后的<<中,第二个输入的对象参数并非以引用形式输入,为什么是合法的?难道说,引用的数据可以以非引用的形式作为函数参数?而非引用的数据不能以引用的形式作为函数参数?
对于这个问题,可以敲代码试一下。
敲了发现加与不加&都可以,或许,这与ostream cout有关吧,这个问题先放一放。

cout << myint2++ << endl;
*//第一个<<处报错:没有与操作数匹配的"<<"运算符*

课程小结:
1、学会区分前置递增和后置递增。
2、后置递增的重载要用占位参数int,与前置递增相区分。
3、前置递增返回引用,后置递增返回值。

在这里插入图片描述

你可能感兴趣的:(4.5运算符重载 加号运算符+ 左移运算符<< 递增运算符++)