《Effective C++讀書筆記》--條款34:區分接口繼承和實現繼承

當我們設計一個類的時候,我們會希望其子類只繼承成員函數的接口,但有時候又希望其繼承接口和實現,但又希望能重寫他們所繼承的接口和實現或者不允許重寫任何東西。我們首先要明確public繼承含義,即is-A的關係,對於基類成立的所有條件,對其public繼承的子類一定成立,反之則不然。

當我們希望子類繼承該函數的接口時,我們可將該函數在基類中定義爲純虛函數,此時基類是不可被實例化的,其中代表的含義是“你必須提供一個該函數的實現,但設計者不干涉你如何去實現他”,比如設計一個人類,喫東西的函數是必須的,但設計者不關心你是用筷子喫還是刀叉喫,只需要實現即可。

當我們希望子類繼承該函數的接口和實現時,我們就可寫一個虛函數(虛函數的繼承要求是函數名,返回值,參數類型均相同,這與子類中和父類的同名函數導致隱藏的規則不同,其中的同名函數值得是函數名相同,而其他參數可以不同)。其代表的含義是“你需要寫一個該函數,如果你自己不想寫,可以使用基類的該函數”,比如一個人類,喫東西的函數是必須的,但同時爲你提供了一個默認用筷子喫東西的函數,你可以自己實現用刀叉喫東西的函數,也可以使用默認的用筷子喫東西的函數。

對於以上兩種情況的結合來說,如果我們需要繼承接口和默認實現,但又不想使我們忘記重寫該函數導致調用了默認版本,我們可以將接口與實現分離開,例如以下代碼

public:
    virturl void eat() = 0;
protected:
    void defaulteat()
    {
         cout << "use chopstick";
    }

如果我們想使用默認版本,就繼承該接口同時在函數體內調用defaulteat(),否則我們就自己加以實現。與該設計類似的實現方法還有一種,也是本人在Qt中遇到過的實現方法:

也就是在子類的實現中調用父類的版本。

最後,對於非虛函數來說,他表示對繼承的子類的一份強制實現,並且任何子類都不應該嘗試去修改。
對於以上關於繼承的討論我們需要知道虛函數,純虛函數和不同成員函數在繼承中的意義,我們在設計類的時候,一要考慮繼承的成本,二要考慮多態的靈活性,

public:
    virtual void eat()
    {
         cout << "chopstick eat";
    }  
class Derive:public Base
{
     void eat()
    {
        Base::eat();
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章