C++重載(主要介紹使用友元函數重載)


重載限制

多數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=2.75*B;

與下面的非成員函數調用匹配:

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;

將轉換為如下語句,從而調用剛才定義的非成員友元函數:

A=operator*(2.75,B);

總之,類的友元函數是非成員函數,其訪問權限與成員函數相同。

 

實際上,按下面的方式對定義進行修改(交換乘法操作數的順序),可以將這個友元函數編寫為非友元函數:

class1 operator*(double m,const class1 &t)

{

  return t*m;//use t.operator*(m)

}

這個版本將class1對象t作為一個整體使用,讓成員函數類處理私有值,因此不必是友元。然而,將該版本作為友元也是一個好主意。最重要的是,它將作為正式類接口的組成部分。其次,如果以后發現需要函數直接訪問私有數據,則只要修改函數定義即可,而不必修改類原型。

提示:如果要為類重載運算符,並將非類的項作為其第一個操作數,則可以使用友元函數來反轉操作數的順序。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM