2010-05-11 86 views
4

我正在開發一個庫,並希望爲我的用戶提供一個與隱藏在名稱空間中的真實實現分開的公共接口。這樣,我就可以只更改HiddenQueue類而不更改myQueue,它只會暴露給用戶。隱藏使用名稱空間的內部類實現

如果我將HiddenQueue的C++代碼放入myQueue.cpp文件,編譯器會抱怨說_innerQueue的類型不完整。我認爲鏈接器能夠解決這個問題。我在這裏做錯了什麼?

// myQueue.h 
namespace inner{ 
    class HiddenQueue; 
}; 

class myQueue{ 

public: 
    myQueue(); 
); 

private: 

    inner::HiddenQueue _innerQueue; 

}; 

/////////////////////////// 

// myQueue.cpp 
namespace inner{ 
    class HiddenQueue{}; 
}; 

回答

6

編譯器需要通過看它在定義的頭文件就知道對象的確切的內存佈局。

您的代碼表示,類MyQueueInnerQueue類型的成員,這將是記憶中的一部分MyQueue對象的佈局。因此,要推導出MyQueue的內存佈局,需要知道InnerQueue的內存佈局。它沒有,因爲你說「哦,它在別處被定義」。

你正在嘗試做什麼與「PIMPLidiom」/「編譯器防火牆」技術密切相關。

爲了解決這個問題,您必須包括HiddenQueue.h在你的頭或聲明_innerqueue作爲指針:

class myQueue { 

public: 
    myQueue(); 

private: 

    inner::HiddenQueue* _pinnerQueue; 
}; 

使用指針是可能的,因爲一個指針有一個已知的內存大小(取決於您的目標體系結構),因此編譯器無需查看HiddenQueue的完整聲明。

+0

+1 PIMPL。這裏有一篇文章來自創造這個術語的人:http://www.gotw.ca/gotw/024.htm – 2010-05-11 14:41:41

+0

嗯,在底線PIMPL招致一些運行時速度成本,併爲您提供便於維護和編譯速度的收益。無可否認,在一般情況下運行時速度成本並不是問題(如果不是這樣,你可能知道這很重要),但恕我直言,在代碼庫中不需要小於一定大小的PIMPL。 – Jon 2010-05-11 14:46:57

1

爲了能夠成爲一個類的成員,你需要有一個定義它,而不僅僅是一個聲明。 (一個聲明足夠用於指針或對類的引用)。

1

您需要提供指針_innetQueue而不是對象本身:

std::auto_ptr<inner::HiddenQueue> _innerQueue; 

搜索表單PIMPL ideom或d,指針

+0

不要將'auto_ptr'用於Pimpl成語,其奇怪的複製/分配語義更麻煩,因爲它們是值得的。 'unique_ptr'或'scoped_ptr'好得多,如果需要的話,你可以編寫一個非常簡單的類。 – 2010-05-11 16:48:07

+0

'unique_ptr'只帶有C++ 0x,'scoped_ptr'需要提升。 'auto_ptr'存在於任何地方。另外,當你的類不可複製時,使用'auto_ptr'更好 - 換句話說:你需要智能指針,標準C++只提供'auto_ptr' – Artyom 2010-05-11 19:08:03