2009-12-05 104 views
6

如果我理解正確,我們至少有兩種不同的實現構圖的方法。 (與智能指針實現的情況不爲簡單起見,我幾乎不使用STL,沒有慾望去學習它。)如何在C++中實現類組合?

讓我們來看看維基百科example

class Car 
{ 
    private: 
    Carburetor* itsCarb; 
    public: 
    Car() {itsCarb=new Carburetor();} 
    virtual ~Car() {delete itsCarb;} 
}; 

所以,這是一種方法 - 我們有一個作爲私人成員指向對象的指針。 我們可以把它改寫成這樣:

class Car 
{ 
    private: 
    Carburetor itsCarb; 
}; 

在這種情況下,我們有一個對象本身作爲私有成員。 (順便說一下,從術語的角度來看,我是否有權將這個實體稱爲對象?)

在第二種情況下,隱式調用默認構造函數不是強制性的(如果需要調用非默認構造函數可能在初始化列表中執行它)和析構函數。但它不是一個大問題...

當然,在某些方面,這兩種情況的差異更明顯。例如,禁止在第二種情況下從Car類的常量方法中調用化油器實例的非常量方法...

是否有任何「規則」來決定使用哪一個?我錯過了什麼嗎?

+1

我想你的意思是「這是被禁止調用由Car類的常量方法化油器實例的非const方法」。 –

+0

@ Laurence Ooops。你當然是對的...... – Wildcat

+8

「[我]不想學習[STL]。」什麼?通過忽略STL,你錯過了C++的一大部分。 – rlbond

回答

7

在這種情況下,我們有一個對象本身作爲私人成員。 (順便說一下,從術語的角度來看,我稱這個實體爲對象嗎?)

是的,你可以說類的「對象」或「實例」。你也可以談論包括數據成員「按值」而不是「按指針」(因爲「按指針」和「按值」是討論傳遞參數的正常方法,所以我希望人們會理解這些條款適用於數據成員)。

是否有任何「規則」來決定使用哪一個?我錯過了什麼嗎?

如果實例被多個容器共享,那麼每個容器應該用指針而不是值包含它;例如,如果一個Employee有一個Boss實例,如果多個Employee實例共享相同的Boss,則通過指針包含Boss。

如果數據成員的生命週期與容器的生命週期不同,那麼可以通過指針包含它:例如,如果數據成員在容器之後實例化,或者在容器之前銷燬,並在容器的生命週期內重新創建,或者如果它對於數據成員爲空是有意義的。

時,必須包含由指針(或通過引用)另一個時間,而不是由值是當所述數據成員的類型是一個抽象基類。

另一個原因,包括指針是,可能允許您更改數據成員的實現而無需重新編譯的容器。例如,如果汽車和化油器在兩個不同的DLL定義,你可能想通過指針包括化油器:因爲這樣你可能能夠通過安裝不同的Carburetor.dll改變化油器的實施,無需重建Car.dll

+0

+1,因爲它們似乎迄今一直被忽視 – Glen

3

組成:如果可能,更喜歡成員。在需要多態性或使用前向聲明時使用指針。當然,如果沒有智能指針,當使用指針時需要手動內存管理。

1

如果Carb與Car有相同的生命週期,那麼在我看來,非指針形式更好。如果您必須更換Carb Car,那麼我會選擇指針版本。

8

我傾向於更喜歡第一種情況,因爲第二種情況要求您在Car.h中#include Carburettor.h。 由於Carburettor是一名私人成員,因此您不應該將其定義包含在實際的Car實現代碼中。使用Carburettor類顯然是一個實現細節,使用Car對象的外部對象不必擔心包含其他非強制性依賴項。通過使用指針,你只需要在Car.h中使用Carburettor的前向聲明。

+0

這兩種情況都是一樣的,所以我低估了這一點。 –

+0

你能更具體嗎,林肯定你沒有明白我的觀點...... – nico

+2

這兩種情況都不一樣。正如nicolascormier指出的那樣,您可以使用前向聲明來避免包含頭文件。也許你應該在downvoting之前瞭解答案。 –

0

一般來說,非指針的版本更容易使用和維護。

但在某些情況下,你不能使用它。例如,如果汽車有多個化油器,並且您希望將它們放在一個數組中,並且化油器構造函數需要參數:您需要通過new創建它們,並將它們存儲爲指針。