2012-07-02 59 views
1

在C++中,如果我有一個類Base,它是一個私有基類DerivedBase沒有虛函數,它會更乾淨,而不是替代繼承與封裝類Encapsulate?我想在這種情況下繼承的唯一好處是可以直接在派生類中訪問基類,而不是通過memberVariable。其中一種或其他做法是否被認爲更好,還是更多是個人風格問題?在沒有虛擬時應該使用私有繼承嗎?

class Base { 
    public: 
    void privateWork(); 
    // No virtual member functions here. 
}; 

class Derived : Base { 
    public: 
    void doSomething() { 
     privateWork(); 
    } 
}; 

class Encapsulate { 
    Base memberVariable; 

    public: 
    void doSomething() { 
     memberVariable.privateWork() 
    } 
}; 
+2

將GoF設計模式拋出窗口,並開始編碼... :) – Gigi

+0

難道你不應該有至少一個虛擬析構函數嗎? –

+0

@LuchianGrigore:如果繼承是私有的,那麼無論如何您都無法通過基指針銷燬派生。所以我會說不一定。 –

回答

2

請記住,繼承模型「Liskov替換」:Foo是一個Bar當且僅當您可以將Foo變量傳遞給期望Bar的每個函數。私有繼承不會對此進行建模。它的模型組合(Foo是以Bar的形式實現的)。

現在,你應該幾乎總是使用第二個版本,因爲它更簡單並且更好地表達意圖:對於不瞭解它的人來說,它不那麼令人困惑。

但是,有時候,私有繼承是很方便的:

class FooCollection : std::vector<Foo> 
{ 
public: 
    FooCollection(size_t n) : std::vector<Foo>(n) {}; 

    using std::vector<Foo>::begin; 
    using std::vector<Foo>::end; 
    using std::vector<Foo>::operator[]; 
}; 

這樣就可以重用一些的vector的功能,而無需手動轉發開始的,結束了2個版本(常量+非常量)和operator[]

在這種情況下,您根本沒有多態:這不是繼承,這是構圖僞裝;您無法使用FooCollection作爲向量。特別是,你不需要虛擬析構函數。

2

如果沒有virtual功能,那麼繼承不應OO使用。請注意,這並不意味着它不能被使用,有一些(有限)的情況,你可能需要(ab)將繼承用於OO之外的其他目的。

+0

有時候,私人繼承對於「相信我的關係」而言是很好的。 –

+0

@MarkB:繼承是最受濫用的功能。作爲一般的經驗法則,繼承是關於代碼重用的,但與大多數人認爲的方向相反:應該使用繼承,以便與您的基礎一起工作的代碼將與您的新類型一起工作(而不是濫用繼承來重用該功能在你的基地)。不應該派生一個沒有虛函數的類(手揮手:即假設沒有靜態多態):使用'Base'對象的現有代碼將無法通過獲取'Derived'引用來做新事情 –

+0

@MarkB:考慮一個具有計時器類的框架,您可以在該計時器類上註冊以進行通知。該框架需要一個特定的接口來註冊定時器,(比如'Notifiable')。現在考慮您要在您的應用程序中提供一個定期計時器,其中使用的確切框架只是一個實現細節。然後你將使用私有繼承來「實現」,即:從客戶的角度來看,你的類不是「Notifiable」的實例,但是在內部,這就是你實現的方式。 –