2011-06-10 184 views
11

是否有可能將聲明前向聲明的類的成員函數聲明爲朋友?我試圖做到以下幾點:聲明前向聲明的類的成員函數爲朋友

class BigComplicatedClass; 

class Storage { 
    int data_; 
public: 
    int data() { return data_; } 
    // OK, but provides too broad access: 
    friend class BigComplicatedClass; 
    // ERROR "invalid use of incomplete type": 
    friend void BigComplicatedClass::ModifyStorage(); 
}; 

所以我們的目標是(i)限制的朋友申報單的方法,及(ii)不包括複雜的類的定義,以減少編譯時間。

一種方法可能是添加一個類作爲中間人:

// In Storage.h: 
class BigComplicatedClass_Helper; 
class Storage { 
    // (...) 
    friend class BigComplicatedClass_Helper; 
}; 

// In BigComplicatedClass.h: 
class BigComplicatedClass_Helper { 
    static int &AccessData(Storage &storage) { return storage.data_; } 
    friend void BigComplicatedClass::ModifyStorage(); 
}; 

然而,這似乎有點笨拙,所以,我認爲必須有一個更好的解決方案!

+0

可能重複的[如何聲明一個朋友是C++中另一個尚未定義的類的成員函數?](http://stackoverflow.com/questions/ 4355660/how-to-declare-a-friend-that-is-a-member-function-of-another-not-defined-clas) – 2011-06-10 18:54:12

+0

感謝您的參考 - 我看到了這個問題;然而,它接受的答案是我想避免的太寬泛的課程級訪問... – hrr 2011-06-10 19:46:43

回答

11

正如@Ben所說,這是不可能的,但您可以通過"passkey"爲該成員函數提供特定的訪問權限。它的工作原理有點像中間輔助類,但恕我直言更清晰:

// Storage.h 
// forward declare the passkey 
class StorageDataKey; 

class Storage { 
    int data_; 
public: 
    int data() { return data_; } 
    // only functions that can pass the key to this function have access 
    // and get the data as a reference 
    int& data(StorageDataKey const&){ return data_; } 
}; 

// BigComplicatedClass.cpp 
#include "BigComplicatedClass.h" 
#include "Storage.h" 

// define the passkey 
class StorageDataKey{ 
    StorageDataKey(){} // default ctor private 
    StorageDataKey(const StorageDataKey&){} // copy ctor private 

    // grant access to one method 
    friend void BigComplicatedClass::ModifyStorage(); 
}; 

void BigComplicatedClass::ModifyStorage(){ 
    int& data = storage_.data(StorageDataKey()); 
    // ... 
} 
+0

不錯!無可否認,我花了一段時間才明白爲什麼複製構造函數必須是私有的...... – hrr 2011-06-10 19:50:27

+0

@hrr:好吧,它不一定是,因爲如果你願意的話,你仍然可以通過引用作爲參考。 – Xeo 2011-06-10 20:11:56

+0

如果複製構造函數是公共的,非特權用戶可以很容易地獲得一個密鑰:'StorageDataKey * key_ptr = 0; StorageDataKey key(* key_ptr);'因此使得私有拷貝構造函數似乎很有意義。 – hrr 2011-06-12 18:14:51

3

不,您不能聲明個別成員函數爲朋友,直到它們被聲明爲止。你只能和全班同學交朋友。

0

是否可以聲明前向聲明類的成員函數爲朋友?

不。當然,編譯器不知道這樣的成員函數。

2

它可能會或可能不會與此有關,但要提醒自己,有一個江湖超越階級的範圍是有用的,功能可以自由漫遊的對象。

例如,我最近需要根據一個其他人的代碼的端口從全局異常處理程序中關閉一個(單例全局靜態)系統錯誤日誌。我的錯誤日誌的正常包含文件與異常處理程序代碼衝突,因爲兩者都想包含「windows.h」,這是因爲我沒有看到。當這個問題以及其他問題說服我,我不能讓我的錯誤日誌類的成員函數預先聲明,我所做的是包所需的功能集成到這樣一個全球範圍內的功能:

void WriteUrgentMessageToErrorLog(const char * message) 
{ 
    ErrorLog::LogSimpleMessage(message); 
    ErrorLog::FlushAccumulatedMessagesToDisk(); 
} 

有的人很講究不惜一切代價維護其班級結構的完整性......並且很少承認使用這些班級的應用程序不可避免地建立在缺乏該結構的東西之上。但它在那裏,明智地使用,它有它的位置。

鑑於這個問題的年齡,我沒有深入瞭解它的相關性。我希望分享的觀點是,有時候這樣一種簡單的包裝機制是一種更清晰,更容易理解的替代物,它具有更多的微妙和聰明之處。微妙和聰明往往會在稍後的日子被需要添加的人完全理解而改變。在你知道它之前,你有一個bug ...