運算符重載:
什麼是運算符重載:
重載的運算符是特殊名字的函數,名字由operator關鍵字加上要重載的運算符組成,如operator+,和其他函數一樣,重載的運算符也包含返回類型、參數列表和函數體。
運算符重載的使用細節:
(1)當一個運算符函數是成員函數,this綁定到了左側運算對象。成員運算符函數的(顯式)參數數量比運算對象的數量少一個。
(2)除了重載的函數調用運算符operator()之外,其他重載運算符不能含有默認實參。
(3)只能重載現有的運算符,無權發明新的運算符。
(4)運算符的重載不改變運算符優先級。
可以被重載的運算符:
+ - * / % ^ & | ~ ! , = < > <= >= ++ -- << >> == != && || ++ -= /= %= &= ^= |=
*= <<= >>= [] () -> ->* new new[] delete delete[]
不可以重載的運算符:
:: .* . ?:
調用重載運算符:
data1 + data2; //普通表達式
operator+(data1,data2); //等價的函數調用
//這兩條語句式等價的,都調用了非成員函數operator+,傳入data1和data2作爲兩個參數
data3 += data4 //基於調用的表達式
data3.operator+=(data2); //對成員運算符的等價調用
//這兩條語句都調用了成員函數 operator+= ,將this綁定到data3的地址,將data4作爲實參傳入了函數
重載運算符作爲成員函數和非成員函數的選擇:
(1)單目運算符應該作爲成員函數(不是必須)
(2)= () [] -> ->*必須是成員函數
(3)複合賦值運算符應該作爲成員函數
(4)所有其他不是這些二元的運算符應該作爲非成員函數
賦值運算符重載標準格式:
T& T::operator=(const T& rhs) {
if (this != &rhs) //檢測自身不等於要賦值的對象
{
//perform assignment
}
return *this;
}
示例代碼:
class Integer {
public :
Integer(int n = 0):i(n){}
const Integer operator+(const Integer& n) const {
return Integer(i + n.i);
}
int print() { return i; }
private:
int i;
};
int main()
{
Integer x(5), y(10), z1,z2,z3;
z1 = x + y; //等同於 z = x.operator+(y)
z2 = x + 3; //Integer類內構造函數被調用Integer(3):i(3){},後z = x.operator+(3)
//z3 = 3 + y; //編譯不通過,3爲第一個參數所以調用int型+,y不爲int型且Integer類內沒有方法把y變爲int型參數
cout <<"Z1:"<< z1.print() << "\tZ2:" << z2.print() << endl;
return 0;
}
類型轉換:
什麼是類型轉換:
類型轉換運算符是類的一種特殊成員函數,它負責將一個類類型的之轉換成其他類型。
標準格式:operator type() const; //type表示某種類型
類型轉換運算符與構造函數:
類型轉換和構造函數都能作T => C的類類型轉換
(1)T(C) //構造函數
(2)operator T() const; //C中的類型轉換
class Orange;
class Apple {
public:
operator Orange() const {} //類型轉換
};
class Orange {
public:
Orange(Apple) {} //構造函數
};
void func(Orange){} //func函數參數爲Orange
int main()
{
Apple ap;
func(ap); //編譯不通過,報錯:應用多個用戶定義的從Apple到Orange的轉換
return 0;
}
但是當構造函數與類型轉換同時存在時,編譯器無法知曉應使用哪種函數來進行轉換,導致錯誤。
解決方法:(1)去掉其中一個函數。
(2)在構造函數前加explicit關鍵字,表示此構造函數只能用於構造,不能用於自動類型轉換
小結:
應避免過度使用類型轉換函數,因其容易形成誤導性,所以要防止意外的事情發生。
一般使用一個專門的函數來調用進行類型轉換,使程序更加一目瞭然發生了什麼。