首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 友元函數全面總結:分類、語法、用途與模板陷阱

     編輯:關於C++

為什麼需要友元

封裝性要求私有成員不可外部訪問,但某些場景(運算符重載、類間協作、效率關鍵路徑)需要打破封裝。友元提供「受控的封裝破壞」:只對特定函數/類開放私有訪問權。

友元分類與語法

1. 普通函數作友元

class Integer {
    int val;
    friend void print(const Integer&);  // 聲明
};
void print(const Integer& obj) {        // 定義(不加 friend、不加 類名::)
    cout << obj.val;
}
  • 聲明位置:public/private 均可,慣例放 public。
  • 調用:像普通函數一樣 print(obj)。

2. 友元類(另一類的所有成員函數均為友元)

class Girl;  // 前置聲明
class Boy {
    string name;
    friend class Girl;  // Girl 所有成員可訪問 Boy 私有成員
};
class Girl {
    void show(Boy& b) { cout << b.name; }  // 直接訪問
};
  • 單向:friend class Girl 只讓 Girl 訪問 Boy,反之不成立。
  • 慎用:破壞封裝範圍最大。

3. 友元成員函數(另一類的某個成員函數為友元)

class Girl;
class Boy {
    string name;
    friend void Girl::show(Boy&);  // 僅 Girl::show 是友元
};
class Girl {
    string name;
public:
    void show(Boy& b) { cout << b.name; }  // 定義在類外或類內均可
};
  • 需前置聲明 Girl,且 show 必須已聲明(可在 Girl 類內聲明,類外定義)。
  • 調用:Girl g; g.show(boy_obj);

4. 模板類中重載 operator<< 的友元聲明(高頻陷阱)

問題:模板類實例化後,operator<< 也需成為對應實例的友元。若直接聲明非模板友元,會導致所有實例共享同一非模板函數,類型不匹配。

正確寫法:

template <class V, class A>
class MGraph {
    // 方案一:函數模板友元(推薦,一對一綁定)
    friend ostream& operator<< <>(ostream&, const MGraph<V,A>&);
    // 方案二:顯式指定模板參數
    friend ostream& operator<< <V,A>(ostream&, const MGraph<V,A>&);
};

定義:

template <class V, class A>
ostream& operator<<(ostream& os, const MGraph<V,A>& G) { ... }
  • <> 必須保留,表示「這是個函數模板」。
  • 若省略 <>,編譯器視為非模板函數聲明,鏈接時找不到匹配實例。

友元 vs 成員函數

特性成員函數友元函數
this 指針有無
調用語法obj.func()func(obj)
訪問私有成員直接通過參數對象
運算符重載左操作數必須是本類對象左操作數可為其他類型(如 ostream&)

最佳實踐

  1. 優先用公有成員函數,僅在必要時用友元(如 operator<<、operator>>、緊密協作的類)。
  2. 友元聲明放在 public 區,語義更清晰。
  3. 模板類友元運算符必須用 friend ... <> 語法。
  4. 避免濫用友元類,改用公有接口或單個友元函數。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved