多數C++運算符都可以用下面的方式重載。重載的運算符不必是成員函數,但必須至少有一個操作數是使用者自定義的類型。下面詳細介紹C++對使用者定義的運算符重載的限制。
1 重載後的運算符必須至少有一個操作數是使用者自定義的類型,這将防止使用者為标準類型重載運算符。是以,不能将減法運算符(-)重載為double值的和,而不是它們的差。雖然這種限制将對創造性有所影響,但可以確定程式正常運作。
2 使用運算符時不能違反運算符原來的句法規則。例如,不能将求模運算符(%)重載成使用一個操作數。
同樣,不能修改運算符的優先級。是以,如果将加号運算符重載成将兩個類相加,則新的運算符與原來的加号具有相同的優先級。
3 不能建立新的運算符。例如,不能定義operator**()函數來表示求幂。
4 不能重載下面的運算符
sizeof:sizeof運算符
.:成員運算符
.*:成員指針運算符
:: :作用域解析運算符
?::條件運算符
typeid:一個RTTI運算符
const_cast:強制類型轉換運算符
dynamic_cast:強制類型轉換運算符
reinterpret_cast:強制類型轉換運算符
static_cast:強制類型轉換運算符
然而,下表中的所有運算符都可以被重載
5 下表中的大多數運算符都可以通過成員或非成員函數進行重載,但下面的運算符值能通過成員函數進行重載
=:指派運算符
():函數調用運算符
[]:下标運算符
->:通過指針通路類成員的運算符
可重載的運算符

除了這些正式限制之外,還應在重載運算符時遵循一些限制。例如,不要将*運算符重載成交換兩個對象的資料成員。
C++控制對類對象私有部分的通路。通常,公有類方法提供唯一的通路途徑,這種限制太嚴格,以至于不适合特定的程式設計問題。在這種情況下,C++提供了另外一種形式的通路權限:友元。
友元有3種:
友元函數
友元類
友元成員函數
通過讓函數成為類的友元,可以賦予該函數與類的成員函數相同的通路權限。
對于一個二進制運算符,如果使用一個類對象和一個double類型進行操作
例如:
A=B*2.75
将被轉換為下面的成員函數調用:
A=B.operator*(2.75);
但下面的語句又如何呢?
A=2.75*B;
從概念上講,這兩個表達式應該相同,但是第二個表達式不對應于成員函數,因為2.75不是類對象。記住,左側的操作數應是調用對象,但2.75不是對象。是以,編譯器不能使用成員函數調用替換該表達式。
解決這個難題的一種方式是——費成員函數(記住,大多數運算符都可以通過成員或非成員函數來重載)。非成員函數不是由對象調用的,它使用的所有值(包括對象)都是顯示參數。這樣,編譯器能夠将下面的表達式:
與下面的非成員函數調用比對:
A=operator*(2.75,B);
該函數的原型如下:
class1 operator*(double m,const class1 &t);
對于非成員重載運算符函數來來說,運算符表達式左邊的操作數對應于運算符函數的第一個參數,運算符表達式右邊的操作數對應于運算符函數的第二個參數。而原來的成員函數則按相反的順序處理操作數,也就是說,double值乘以class1值。
使用非成員函數可以按所需的順序獲得操作數(先double,然後是class1),但引發了一個新問題:非成員函數不能直接通路類的私有資料,至少正常非成員函數不能通路。然而,有一類特殊的非成員函數可以通路類的私有成員,它們被稱為友元函數。
建立友元的第一步是将其原型放在類聲明中,并在原型聲明前加上關鍵字friend:
friend class1 operator*(double m,const class1 & t);
該原型意味着下面兩點:
雖然operator*()函數是在類聲明中聲明的,但他不是成員函數,是以不能使用成員運算符來調用;
雖然operator*()函數不是成員函數,但它與成員函數的通路權限相同。
第二步的編寫函數定義。因為它不是成員函數,是以不要使用成員限定符::。另外,不要再定義中使用關鍵字friend。定義應該如下:
class1 operator*(double m,const class1 &t)
{}
有了上述聲明和定義後,下面的語句:
A=2.75*B;
将轉換為如下語句,進而調用剛才定義的非成員友元函數:
總之,類的友元函數是非成員函數,其通路權限與成員函數相同。
實際上,按下面的方式對定義進行修改(交換乘法操作數的順序),可以将這個友元函數編寫為非友元函數:
{
return t*m;//use t.operator*(m)
}
這個版本将class1對象t作為一個整體使用,讓成員函數類處理私有值,是以不必是友元。然而,将該版本作為友元也是一個好主意。最重要的是,它将作為正式類接口的組成部分。其次,如果以後發現需要函數直接通路私有資料,則隻要修改函數定義即可,而不必修改類原型。
提示:如果要為類重載運算符,并将非類的項作為其第一個操作數,則可以使用友元函數來反轉操作數的順序。。