运算符重载
我们知道运算符重载有两种形式,成员函数重载和友元重载。为什么会有两种形式,什么时候使用这两种形式,下面进行解释。
成员重载
-
我们知道运算符调用是由运算符左边的变量调用的
total=coding+fixing; total=coding.operator+(fixing);
有几点注意,首先返回值尽量返回副本而不是引用,即便那很花时间。参数设置为const。
-
重载后的操作运算符至少有一个是用户自定义类型,不能两个都是内置类型。这是为了编译器防止你篡改自带的运算法则。
-
重载的操作符的优先级不变。
-
=, (), [], ->只能通过成员函数重载,可以想到,如果你想要使用这个运算符,那么一定要使用某个实例变量调用该运算符,所以使用成员函数而不是友元函数。
如果重载运算符实现计算,比起创建一个变量然后想加赋值,更好的方法是直接创建一个结果的变量,即使用构造函数。
友元
请看下面的例子。
我们都知道成员函数重载运算符,调用者是运算符左边的变量,但是假如……
total=5+coding;
按照刚才的解释,这里应该是常量5调用重载后的运算符,但是这做不到,你必须把coding放到左边才行。这样client造成了极大的不方便,为了解决这种问题,我们可以将运算符左右两边的变量看作参数,传入重载运算符函数。但是这样函数就不再是成员函数,所以就无法直接访问类内的私有成员。
为了既让函数不是成员函数但是又能和成员函数一样访问类内的私有变量,就需要使用friend。
这就是是由友元函数的原因。
友元分为以下几类
-
友元函数
-
友元类
-
友元成员函数
以一个很常用的例子
ostream& operator<<(ostream& os, const Time& t){
os<<t.hours<<"hours, "<<t.minutes<<"minutes.";
return os;
}
不知道你有没有想过这里为什么返回os的运用。
请看下面的调用。
cout<<"Trip time: "<<trip<<" (Tuesday)\n";
在第一个<<正常使用字符串的运算符,第二个使用我们重载后的<<,这个时候,如果你返回void,那么在最后一个<<这里将出错,所以为了能够实现一连串的输出,我们需要继续返回ostream,事实上,c++标准库也是这样做的。
类型转换
-
将内置类型转为类类型:这种转换编译器使用一个参数的构造函数实现的,或者有多个参数但是只有一个参数没有默认值。同样,我们可以使用explicit禁止隐式转换。
class Stonewt{ private: int stone; double pounds; public: Stonewt(double lbs){ stone=(int)lbs/14; pounds=lbs; } Stonewt(int stn,double lbs=0){ stone=stn; pounds=stn*14+lbs; } }; double myDou=20.1; Stonewt myWt=myDou; //调用double参数的构造函数 int myI=13; Stonewt myWt_=myI; //调用有默认参数的构造函数
-
将类类型转换为内置类型:这一部分的实现使用C++的转换函数,定义格式如下
(explicit) operator typename() (const);
虽然该函数没有指出返回值,但是依旧需要和typename相同类型的返回值。
这样你可能发现,在友元部分,我们说因为操作符左边并不是类类型,无法调用重载操作符,所以我们可以使用强制类型转换将内置类型使用构造函数变成类类型,然后调用重载运算符。
事实告诉我,这样是可行的。但是我们应尽量避免这样频繁进行类型转换。