4.5 运算符重载
所谓两个自定义数据相加,即两个结构体,或者两个对象相加。等操作。
#include<iostream>
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、在运算符重载的过程中,也可以发生函数重载
根据函数的参数类型不同,发生函数重载。
问题1:为什么类,对象,在做函数参数的时候,总是以引用的方式?
为了实现代码Person p;cout<<p.;对左移运算符<<进行重载。
#include<iostream>
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,但是实际上想达到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 <<p;,其中p是Person类型的对象。对左移运算符<<进行重载。
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 递增运算符++重载
利用递增运算符++,自己写一个整形变形。自己写一个,模拟一个整形变量。
回顾一下递增
//前置递增
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<iostream>
using namespace std;
#include<string>
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、前置递增返回引用,后置递增返回值。