运算符重载其实是另一种形式的函数调用,这种形式可以给我们类对象赋予各种类似于基本数据类型的运算能力。
C语言中也有运算符的重载,比如说 * 和 &,如果不去思考重载实现的细节与规则,那么这一部分的学习会相当的通俗易懂。但是,看完下边这个表的时候你有没有想过为什么?
图1:不同运算符的重载函数类型
这里我们先聊一聊重载运算符的基本规则:
- 重载运算符的功能应参照该运算符作用于基本类型数据时候时所实现的功能
- 用于类对象的运算符一般必须重载,”=“和”&“不必用户重载,系统默认提供
- 重载不能改变运算符操作数,重载运算符的函数不能有默认的参数
- 重载后的运算符必须由至少一个参数是用户自定义的类型
- 重载不能改变运算符的优先级和结核性
不能重载的运算符有:
图2:不能重载的运算符
然后咱们回到图1:
为什么运算符的重载要采用这么多不同的类型函数?
1,运算符的操作会修改类对象的属性时,必须采用成员函数
2,第一个操作数为非对象时,必须使用友元函数,如<<和>>
3,重载双目运算符时,第一个操作数必须是类对象才能调用改类的重载成员函数,类的this指针会被绑定到运算符的左侧的运算对象。
规则终于讲完了,现在我们开始实例测试:
1,双目运算符的成员与友元重载
首先我们来看一下成员重载+号和友元重载-号
class Person {
public:
friend Person operator-(Person p1, Person p2);
Person() :_age(0) {};
Person(int a) {
this->_age = a;
}
Person operator+(int a) {
return _age + a;
}
void printfInfo() {
cout << " my age = " << _age << endl;
}
private:
int _age;
};
Person p1(10);
Person p2 = p1 + 1; //1调用隐式转换,然后p1调用重载+号
Person p2 = 1 + p1; //error,1无法调用隐式转换
Person p3 = 1 - p1 ; //1调用隐式转换,然后调用重载-号
Person p3 = p1 - 1; //1调用隐式转换,然后p1调用重载-号
2,<<左移运算符重载
ostream & operator<<(ostream & cout, Person & p)
{
cout << " my age = " << p._age;
return cout;
}
Person p1(10);
cout << p1 << endl;
此处 cout 必须用引用方式传参,返回值也必须是引用,因为整个程序中只能存在一个cout对象,目测是一个单例对象(有可能不是)。但是暂时看不到源码无法求证。目前可以测试得到的准确答案是:cout 没有公有的拷贝和默认构造。
3,为什么重载 = , [ ],(),->只能用成员函数?
我们尝试一下用友元函数重载会直接看到报错:
编译器在这里很不客气,根本就不让我们用友元进行这样的尝试。既然友元用不了,那么我们重新写一个类,让他的属性都是公有的,以全局函数再次尝试一下。
同样还是不行,然后看了很多相关的帖子,总结如下:
关于 = 重载:我们知道一个c++类,如果没有为其提供赋值操作符重载函数,编译器也会隐式的定义,这样倘若再定义全局赋值运算符重载函数,将会发生二义性。
关于 [ ] 和 ->重载:如果们可以突破只能用成员函数的限制,将[]操作符重载函数是全局(友缘)的,也就是没有了该函数的左操作数是this指针的限制,程序员可以任意定义左操作数的类型,类似的,就会出现6=c, 6(c), 6->c这样的代码,显然这样的代码是错误的。