运算符重载复习
0.引言
1.使用 operator 关键字引入重载函数
-
函数参数个数与运算操作数个数相同,至少一个为类类型(不能全部都是内建类型)
#include<iostream> #include<vector> #include<string> struct Str { int val; }; //均为内建类型,非法 auto operator +(int x, double y){ } int main(){ Str x; Str y; x + y;//合法 }
-
除 operator() 外其它运算符不能有缺省参数(这里的operator()是重载小括号"()"的意思)
struct Str { int val = 3; //operator() 可以带缺省参数 //典型的运算符重载 auto operator () (int y = 3){ return val + y; } };
-
可以选择实现为成员函数与非成员函数
- 通常来说,实现为成员函数会以 *this 作为第一个操作数(注意 == 与 <=> 的重载)
#include<iostream> #include<vector> #include<string> struct Str { int val = 3; //operator() 可以带缺省参数 //典型的运算符重载 auto operator () (int y = 3){ return val + y; } auto operator +(Str x){ Str z; z.val = val + x.val; return z; } }; int main(){ Str x; Str y; Str z = x + y;//x-->this, y为输入的参数 ---- std::cout<< x(5) <<std::endl;//8 std::cout<< x() <<std::endl;//6 }
2.根据重载特性,可以将运算符进一步划分
- 可重载且必须实现为成员函数的运算符( =,[],(),-> 与转型运算符)(可重载的基本都可以重载为成员函数,但这几个必须重载为成员函数)
- 可重载且可以实现为非成员函数的运算符
- 可重载但不建议重载的运算符( &&, ||, 逗号运算符)
- C++17 中规定了相应的求值顺序但没有方式实现短路逻辑
- 不可重载的运算符(如 ? :运算符)
3.运算符重载
-
对称运算符通常定义为非成员函数以支持首个操作数的类型转换
#include<iostream> #include<vector> #include<string> struct Str { Str(int x) : val(x) {} // 全局域的函数 // 类内定义友元函数的典型应用 friend auto operator +(Str input1, Str input2){ //使用友元来更改权限 return Str(input1.val + input2.val); } private: int val; }; int main(){ Str x = 3; Str z = 4 + x;//合法 }
-
移位运算符一定要定义为非成员函数,因为其首个操作数类型为流类型
//std::cout<<std::enl;就是重载了移位运算符 //ostream输出流 friend auto& operator << (std::ostream& ostr, Str input) { ostr << input.val; return ostr;//为什么要返回ostr - 为了支持:std::cout<< x << z;这种连续操作 - 如果不返回,就只能输出一次! }
-
赋值运算符也可以接收一般参数
// 第一参数为*this // 拷贝赋值运算符 Str& operator=(const Str& input){ val = input.val; return *this; } // = 是二元操作符 Str& operator=(const std::string& input){ val = static_cast<int>input.size(); return *this; }
-
operator [ ] 通常返回引用–举例:使用重载[ ]模拟数组的访问操作!
- 返回引用才能支持写操作,否则只支持读操作! int& operator[](int id) { return val; } //重载一个const属性的操作 int operator[](int id) { return val; }
-
自增、自减运算符的前缀、后缀重载方法
//我们需要一种办法去判断是前缀自增还是后缀自增 Str& operator++ ()//没有参数:前缀自增(自减同理) { ++val; return *this; - 为什么要返回*this - 为了能实现类似++(++x)这样的操作 } //有参数:后缀自增(自减同理),input变量没有实际意义 Str operator++ (int) { - 这也是平时代码中尽可能使用前缀自增的原因 Str tmp(*this);//拷贝构造,可能很耗时 ++val; return tmp;//返回的是副本,然后再++ }
-
使用函数调用运算符构造可调用对象
#include<iostream> #include<vector> #include<string> struct Str { Str(int p) :ptr(p) { } //operator()函数调用运算符:ORB-SLAM2的特征点提取就是用的这个 int operator() () { return val; } int operator() (int x, int y, int z) { return val+x+y+z; } private: int val; }; int main(){ Str obj(100); std::cout<< obj() <<std::endl; std::cout<< obj(1,2,3) <<std::endl; }
ORB-SLAM2中的函数调用操作符重载:
- 声明 void operator()( cv::InputArray image, cv::InputArray mask, std::vector<cv::KeyPoint>& keypoints, cv::OutputArray descriptors); - 调用 (*mpORBextractorLeft)(im,cv::Mat(),mvKeys,mDescriptors);