运算符重载
- 重载:在同一个作用域内定义多个同名函数,这些函数具有不同的参数列表或函数体。泛型:允许编写代码时不指定具体的数据类型
- 重载运算符,可以重新定义运算符的行为
- 几元运算符:包含几个运算对象,重载的函数的行为应与内置版本一致
- 声明运算符重载函数: 返回类型 + operator + 运算符 +(参数列表(运算对象的数目));
- 注意:重载运算符,或者是类的成员,或者至少包含一个类类型参数,
- 如果作为成员函数,左侧运算对象为隐式this指针,所以显示的参数列表数量应少一个
- 调用方式:
- 显示调用重载函数:非成员函数,不用类实例调用,成员函数需要类实例+成员访问运算符,两者都传入实参(运算对象),
- 隐式调用重载函数,显示调用运算符:直接使用运算符,和运算对象
- 对于运算符重载函数:有时作为成员函数更好,有时仅能作为非成员函数
实例:
- IO运算符:必须是非成员函数,因为如果是成员函数,左侧运算对象将为类,而非iostream,这是不符合规范的,
- io对象为非常量引用,因为会改变自身和不可拷贝,返回值为自身的引用,因为不可拷贝
- //
- 算术运算符:可以为非成员的
- 会接受常量引用,并返回新值,不要返回临时对象的引用
- //
- 赋值运算符:应为成员函数
- 接受常量引用,并返回 *this的引用
- //
- 下标运算符[]:应为成员函数
- 接受size_t下标,返回类数据成员的元素引用
- //
- 递增递减运算符:应为成员函数
- 空参数列表,返回 *this的引用,
- 如何区分前置和后置?前置++a:先自增,再返回值,后置a++;先返回值,再自增
- 对于后置版本,会传递不被使用的int形参,显示调用后置版本:传入实参,实参不参与运算
函数对象
- 重载()函数调用运算符的类,被称为函数对象,这个类就成为了可调用对象
- 使用重载函数的方式,就像调用函数一样调用类
- //
- 如何区分创建类对象,还是调用重载()的函数?
- 调用函数和普通成员函数一样,都是要通过类实例调用,知识没有了成员访问运算符和函数名,而对于创建类实例,需要类名
- //
- 对于算法的谓词应传入可调用对象,其中编写了lamba后,编译器将产生一个未命名的函数对象(包含operator()),并且形参列表,函数体,返回值,都和lambda没有差异,
- 所以完全写一个函数对象,并在谓词传入函数对象实例
- 对于对于捕获列表,按引用捕获,类对象可以直接使用对象,但对于值捕获,将会拷贝到lambda中,所以类会建立数据成员,和构造函数,通过非默认构造,初始化成员
- 因为是非默认构造,在写等价类是,传入的谓词,的类实例必须显示传递值捕获的变量
- 对于谓词,我们可以传入STL库中的表示运算符的函数对象,它们都是模板类,可以直接传入类实例
- //
- 对于定义的function对象,我们存入可调用对象,但是不能存入有函数重载的可调用对象,将出现二义性
- 但是可以使用函数指针或lambda去替代特定版本