14.1基本概念
重载运算符和重载其他函数差不多,运算符有多少参数,那么重载运算符就有多少参数.不同的是重载运算符有名字方面的限制,是operator加上运算符号.且除了函数调用运算符()之外,不允许有默认实参.
以上其中逻辑与运算符,逻辑或运算符,逗号运算符,取地址运算符不推荐重载.
并且重载时尽量与内置的运算符含义一致.(不要把加号重置成减法)
当我们把重载运算符定义为成员函数时时,左侧的运算对象必须是运算符所属的一个对象.
我这边定义一个简单的类,有两个成员函数,接下来演示重载运算符都按照这个类.
class Student {
public:
int age;
string name;
Student(int a, string n) :age(a),name(n){}
};
14.2输入和输出运算符
输入输出运算符必须是非成员函数.
14.2.1重载输出运算符<<
一般情况下,输出运算符的第一个形参是非常量的ostream对象的引用.非常量是因为可能会改变ostream的状态.引用是因为我们无法拷贝ostream对象.第二个形参通常是常量的引用.为了和其他输出运算符保持一致(也为了链式编程),要返回ostream形参.
//定义在Student类外
ostream& operator<<(ostream& cout,const Student& s) {
cout << s.name << ' ' << s.age;
return cout;
}
通常重载输出运算符为了打印类的信息更加便利.若需打印类的私有成员,则需将IO运算符声明为友元.
14.2.2重载输入运算符>>
和重载输入运算符差不多,但是输入运算符需要处理输入可能失败的情况.
14.3算术和关系运算符
如果同时定义了算术运算符和相关的符合赋值运算符(例如+和+=),则通常情况下应该使用复合赋值来实现算术运算符.
14.3.1相等运算符
以下例子为定义若两个Student类的对象的年龄一致则返回true.定义与Student类外.
bool operator==(const Student& s1, const Student& s2) {
return s1.age == s2.age;
}
14.3.2关系运算符
和上面的相等运算符差不多,只不多定义的是<,>,<=,>=.需要注意的是定义好统一的排序顺序.值得一提的是,如果map的键类型为自定义类型,那么必须定义好关系运算符,因为map自动按照键值来升序排列,没有定义好类的排列顺序则会出问题.
14.4赋值运算符
这个在上一章有介绍,就是移动赋值运算符.
14.5下标运算符
必须是类的成员函数.
为了和原始的定义兼容,通常返回所访问的元素的引用作为返回值.
14.6递增和递减运算符
不是必须但是建议是类的成员函数.
为了区分前置和后置运算符,在后置版本的参数列表中添加一个不被使用的形参.并且后置模式为了和内置的版本保持一致,需要在数值加一之前先保存住原值,然后加一之后再将原值返回出去.
//前置版本递增运算符
Student operator++() {
this->age += 1;
return *this;
}
//后置版本递减运算符
Student operator++(int) {
Student temp = *this;
this->age += 1;
return temp;
}
除了正常使用递增递减符号之外,也可以显式地使用(将其当作函数).
Student s1(18, "张三");
s1.operator++(); //调用前置版本
s1.operator++(0); //调用后置版本,其中0无实意,只要和前面定义的形参类型一致即可
14.7成员访问运算符
箭头运算符必须是类的成员.
解引用非必要但是建议为类的成员.
(但我不是很理解为什么要重载这类运算符)
14.8函数调用运算符
如果一个类定义了调用运算符(),那么该类的对象称为函数对象(仿函数).因为可以把类的对象当作函数名来使用.
例如我在开头定义的类内加上:
void operator() (){
cout << "my name is " << this->name << endl;
}
然后可以像调用函数一样使用Student的对象.
14.8.1 lambda是函数对象
重载了函数调用符后,可以用类来代替lambd.
例如在使用sort算法时,第三个参数可以写上类名加上().
14.8.2标准库定义的函数对象
通常和STL的算法配套使用.
英文好的应该一看名字就知道是这么用的了,这里不多介绍.
14.8.3可调用对象与function
C++中可调用对象有:函数,函数指针,lambda表达式,bind创建的对象,重载了函数调用运算符的类.
两个不同类型的可调用函数可以共享一种调用形式.调用形式指明了返回的类型以及传递给调用的实参类型.
int<int,int>
上面这个是一个函数类型,表示为接收两个int的参数,返回值为int.
我们可以使用定义在functional头文件中的function来表达函数类型.
14.9重载,类型转换与运算符
类型转换运算符是类的一种特殊成员函数,它负责将一个类类型的值转换成其他类型,形式如下:
operator type() const;
应当避免过度使用类型转换函数.
并且应当避免有二义性的类型转换.