2011-04-25 126 views
4

我寫一個C++頭在我定義了一個隱藏在頭一個C++類,而無需使用具名命名空間

class A { 
    // ... 
}; 

,我想從外面的世界隱藏的(因爲它可能會改變,甚至在此標題的未來版本中將被刪除)。

還有一個B類在具有類A​​的一個對象作爲成員相同的標題:

class B { 
public: 
    // ... 

private: 
    A a_; 
}; 

什麼是從外界隱藏類A的一個適當的方式?

如果我把A的定義不具名命名空間,編譯器會發出警告,所以我認爲,由於具有內部鏈接的問題,我應該做些別的事情。

+0

另請參閱[使用頭文件中的匿名命名空間](https://stackoverflow.com/q/357564/608639),[隱藏類頭中的類類型](https://stackoverflow.com/q/ (https://stackoverflow.com/q/14092705/608639),[在不使用未命名的名稱空間的情況下將C++類隱藏在標題中](https://3525552/608639),[如何隱藏C++中的類?] /stackoverflow.com/q/5780918/608639) – jww 2017-09-28 23:22:53

回答

5

你可以做一個內部類:

class B 
{ 
    class A { /* ... */ }; 
    A a_; 
} 
+0

哦,是的,那當然會起作用。對不起,我忘了提到B是一個類模板(有很多參數),我實現了A自己的拷貝構造函數和賦值操作符,所以將類A(作爲嵌套類)依賴於所有模板B的參數你也許有另一個建議嗎? – Bjoern 2011-04-25 17:17:17

+0

@Bjoern我不確定我是否完全理解你。 'template class B'並且在它裏面'class A {A(const A&); A&operator =(const A&); };'不會是個問題,對吧?我不明白你對A類的意思是依賴於B的模板參數。 – 2011-04-25 17:24:19

+0

根本不是,但'typename B :: A'和'typename B :: A'將會不同,儘管'A'並不真正依賴於B的任何模板參數。這就要求我寫'class A {template A(const typename B :: A &) {}; template A&operator = (const typename B :: A &) };' – Bjoern 2011-04-25 17:29:25

1

而不是class B持有A對象,有它持有A*代替(或shared_ptr<A>,或unique_ptr<A>等)。這樣class B只需要的class Aclass A向前聲明可以class B的源文件內完全確定。

1

如果A是B的實現細節,請不要將其定義放在標題中。相反:

class B { 

    ... 
    class A * myA; 
}; 

然後把A的定義放在B實現(即.cpp)文件中。

+0

對不起,我真的忘了提到B類實際上是一個模板(取決於許多參數),並且庫僅作爲單個頭來使用,而沒有單獨的實現.cpp文件。 – Bjoern 2011-04-25 17:20:55

8

去了解它在C++中正確的做法是PIMPL成語。另一種解決方法是將要隱藏的類放入嵌套名稱空間中,該名稱空間通常稱爲detail。但是這並不會完全保密,因爲用戶仍然會受到依賴關係的影響,並且可以直接使用它。

+0

本週大師指導+1 – hammar 2011-04-25 17:23:01

1

此類不屬於公共API且不應使用的文檔。

在C++中,你必須,因爲你沒有什麼其他選擇,以你的庫代碼鏈接信任的程序。 C++限制了「訪問控制」功能,其中許多功能可以被繞過或濫用,因此您更好地尊重您的API客戶端並建立信任。

如果你設計你的API很容易被正確使用,很難使用不當無意,那麼你將幫助你的客戶,這是幾乎是你的錯,如果你的客戶辜負你的界面。

1

具名命名空間是沒用的,反正,因爲它不僅保護agains多個定義。你可以做的是使用pImpl成語,如其他答案中所述,或者使用detail命名空間。爲升壓工程罰款:

namespace detail{ 
    class A{ 
    // ... 
    }; 
} 

class B{ 
public: 
    // ... 
private 
    A a_; 
}; 

任何人在detail命名空間的東西搞亂是自找麻煩。或者可能更加模糊它

namespace _b_impl_detail{ 
    // ... 
}; 

任何人現在觸摸內部的任何東西都應該在腳下射擊。:)