算符重載的作用是什麼?它允許你為類的用戶提供一個直覺的接口。 算符重載允許C/C++的運算符在用戶定義類型(類)上擁有一個用戶定義的意義。重載的算符是函數調用的語法修飾:
class Fred {
public: // …
};
#if 0 // 沒有算符重載:
Fred add(Fred, Fred);
Fred mul(Fred, Fred);
Fred f(Fred a, Fred b, Fred c)
{
return add(add(mul(a,b), mul(b,c)), mul(c,a)); // 哈哈,多可笑…
}
#else // 有算符重載:
Fred operator+ (Fred, Fred);
Fred operator* (Fred, Fred);
Fred f(Fred a, Fred b, Fred c)
{
return a*b + b*c + c*a;
}
#endif
算符重載的好處是什麼?
通過重載類上的標准算符,你可以發掘類的用戶的直覺。使得用戶程序所用的語言是面向問題的,而不是面向機器的。 最終目標是降低學習曲線並減少錯誤率。
有什麼算符重載的實例?這裡有一些算符重載的實例:
myString + yourString 可以連接兩個 std::string 對象
myDate++ 可以增加一個 Date 對象
a * b 可以將兩個 Number 對象相乘
a[i] 可以訪問 Array 對象的某個元素
x = *p 可以反引用一個實際“指向”一個磁盤記錄的 "smart pointer" —— 它實際上在磁盤上定位到 p 所指向的記錄並返回給x。
但是算符重載使得我的類很丑陋;難道它不是應該使我的類更清晰嗎?算符重載使得類的用戶的工作更簡易,而不是為類的開發者服務的! 考慮一下如下的例子:
class Array {
public:
int& operator[] (unsigned i);
};
inline
int& Array::operator[] (unsigned i)
{ // …
}
有些人不喜歡operator關鍵字或類體內的有些古怪的語法。但是算符重載語法不是被期望用來使得類的開發者的工作更簡易。它被期望用來使得類的用戶的工作更簡易:
int main()
{
Array a;
a[3] = 4; // 用戶代碼應該明顯而且易懂…
}
記住:在一個面向重用的世界中,使用你的類的人有很多,而建造它的人只有一個(你自己);因此你做任何事都應該照顧多數而不是少數。
什麼算符能/不能被重載?大多數都可以被重載。C的算符中只有 . 和 ? :(以及sizeof,技術上可以看作一個算符)。C++增加了一些自己的算符,除了::和.*,大多數都可以被重載。 這是一個下標算符的示例(它返回一個引用)。先沒有算符重載:
class Array {
public:
int& elem(unsigned i) { if (I > 99) error(); return data[i]; }
private:
int data[100];
};
int main()
{
Array a;
a.elem(10) = 42;
a.elem(12) += a.elem(13);
}
現在用算符重載給出同樣的邏輯:
class Array {
public:
int& operator[] (unsigned i) { if (I > 99) error(); return data[i]; }
private:
int data[100];
};
int main()
{
Array a;
a[10] = 42;
a[12] += a[13];
}
我能重載 operator== 以便比較兩個 char[] 來進行字符串比較嗎?不行:被重載的算符,至少一個操作數必須是用戶定義類型(大多數時候是類)。 但即使C++允許,也不要這樣做。因為在此處你應該使用類似 std::string的類而不是字符數組,因為數組是有害的。因此無論如何你都不會想那樣做的。
我能為“冪”運算創建一個 operator** 嗎?不行。 運算符的名稱、優先級、結合性以及元數都是由語言固定的。在C++中沒有operator**,因此你不能為類類型創建它。
如果還有疑問,考慮一下x ** y與x * (*y)等同(換句話說,編譯器假定 y 是一個指針)。此外,算符重載只不過是函數調用的語法修飾。雖然這種特殊的語法修飾非常美妙,但它沒有增加任何本質的東西。我建議你重載pow(base,exponent)(雙精度版本在中)。
順便提一下,operator^可以成為冪運算,只是優先級和結合性是錯誤的。
如何為Matrix(矩陣)類創建下標運算符? [Recently changed so it uses new-style headers and the std:: syntax (on 7/00). Click here to go to the next FAQ in the "chain" of recent changes.]