动机:x+y 的写法比 add(x,y)的写法更加简洁
但是编译器并不能理解把“+”应用到任意两对象上。
Str Add(Str x, Str y)
{
Str z;
z.val = x.val+y.val;
return z;
}
auto operator + (Str x, Str y)
{
Str z;
z.val = x.val + y.val;
return z;
}
在运算符重载的过程中,我们可以把运算符重载为成员函数或者非成员函数。
参考资料: Cpp reference
对称运算符的重载
什么叫对称运算符?
可以支持对象顺序的转换的运算,比如+
对称运算符不建议定义成成员函数。
Why?
因为如果运算处理的第一个变量需要隐式类型转换,那么该运算很有可能无法执行。
而非成员函数可以支持首个操作符的类型转换。
如果非成员函数的操作涉及到成员的隐式变量时, 我们可以使用友元去处理变量。
类内定义友元函数的经典使用
移位运算符的重载
移位运算符通常不声明为成员函数。
利用ostream的引用来表示任何意义上的输出流
auto& operator << (std::ostream& ostr, Str input)
{
ostr <<input.val;
return ostr;
}
这样我们就可以打印成员了!
赋值运算符
经典的自定义赋值操作。
operator[ ]通常返回引用,否则返回值不易被修改。
自增自减的重载
operator++ (int input)
//后缀自增
operator-- ()
//前缀自增
前缀自增的实现,需要返回引用
后缀自增的实现首先要需要拷贝构造,临时构造对象,然后返回tmp的值。
对比前缀和后缀自增的实现,明显前缀自增更容易实现,前缀自增的性能更好。
解引用运算符(*)的重载
成员访问运算符,->可以重载,.不可以。
下图实现了对解引用运算符的重载。
成员访问运算符(->)的重载
当成员访问运算符返回的对象不是指针,而是对象的时候,系统会试图寻找返回的对象类型是否定义了成员访问运算符的重载,然后继续调用返回对象的成员访问运算符。
函数调用()运算符重载
类型转换运算符
函数声明为 operator type() const,
特点: 没有显式的指出返回类型。
避免隐式转换
添加explicit 关键词,系统将无法执行自动的类型转换
比如对于类型转换运算符添加object,系统将不能把它自动的转换为int
或者,如上图,这将无法自动的将int 转换为str。
虽然不能隐式转换,但是我们可以通过static_cast 进行隐式转换。
注意,针对explicit bool,编译器能视情况进行仍然进行隐式转换。
3-way comparation