Effective C++讀書筆記

條款32:確定public繼承塑造出is-a關係

如果你另class D以public形式繼承class B,你便告訴編譯器(以及你的代碼閱讀者)說,你D的每一個對象同時也是類型爲B的一個對象.

public繼承遇到的問題:

class Bird{
    public:
        virtual void fly(); //bird can fly
        ...
    };
 class Penguin:public Bird{    //Penguin is a kind of bird
        ...
 };
企鵝(penguin)是一種鳥是事實,鳥可以飛也是事實,但這個繼承體系說企鵝可以飛,顯然不嚴謹

既然不是所有的鳥都可以飛,就這樣處理繼承體系:

class Bird{
        ...//沒有聲明fly函數
    };
class FlyingBird:public Bird{
    public:
        virtual void fly();
        ...
};
    class Penguin:public Bird{
        ...  //沒有聲明fly函數
    };

存在於classes之間的關係,is-a,has-a,is-implemented-in-terms-of(根據某物實現出)

請記住:

★★"public繼承"因爲is-a.適用於base class身上的每一件事情一定也適用與derived class身上,因爲每一個derived class對象也都是一個base class對象.

條款33,避免遮掩,繼承而來的名稱


class Base { 
private: 
    int x; 
public: 
    virtual void mf1() = 0; 
    virtual void mf1(int); 
    virtual void mf2(); 
    void mf3(); 
    void mf3(double); 
}; 
class Derived : public Base { 
public: 
    virtual void mf1(); 
    void mf3(); 
    void mf4(); 
};

以作用域爲基礎的“名稱遮掩規則”並沒有改變,因此base class內所有名爲mf1和mf3的函數都被derived class內的mf1和mf3函數遮掩掉了。

Derived d; 
int x; 
d.mf1(); 
d.mf1(x);//錯誤,Derived::mf1遮掩了Base::mf1 
d.mf2(); //調用base::mf2() 
d.mf3(); 
d.mf3(x);//錯誤,Derived::mf3遮掩了Base::mf3

即使base class和derived classes內的函數有不同的參數類型也適用,而且不論函數是virtual或non-virtual也適用,和函數裏的double x遮掩全局int x一樣,Derived內的函數mf3遮掩了一個名稱爲mf3但類型不同的函數

這些事防止你建立derived class時附帶的從疏遠的base classes繼承重載函數,如果想繼承重載函數 則使用using

列:

你可以用using聲明式達成目標:

class Derived : public Base { 
public:
//base class內的public名稱在publicly derived class內也應該是public。 
    using Base::mf1;    // 讓base class內爲mf1和mf3的所有東西 
    using Base::mf3;    //在Derived class作用域內都可見(並且public) 
    virtual void mf1(); 
    void mf3(); 
    void mf4(); 
};
Derived d; 
int x; 
d.mf1(); 
d.mf1(x);//現在沒問題了,調用Base::mf1 
d.mf2(); 
d.mf3(); 
d.mf3(x);//現在沒問題了,調用Base::mf3

這意味着如果你繼承base class並加上重載函數,而你又希望重新定義或覆寫(推翻)其中一部分,那麼你必須爲那些原本會被覆蓋的每一個名稱引入一個using聲明式,否則某些你希望繼承的名稱會被覆蓋。

★假設Derived以private形式繼承Base,而Derived唯一想繼承mf1是哪個無參數版本,using聲明將排不上用場,因爲using聲明會令繼承而來的某給定名稱之所有同名函數在derived class中都可見,實現這一功能需要不同的技術:轉交函數(forwarding function)

class Base{
public:
	virtual void mf1() = 0;
	virtual void mf1(int);
    ...//與前同
};
class Derived:private Base
{
public:
	virtual void mf1()
	{
		Base::mf1();
	}
	...
};
...
Derived D;
int x = 10;
D.mf1();//很好,調用的是Derived::mf1()
D.mf1(x)//錯誤Base::mf1()被遮掩了







發佈了66 篇原創文章 · 獲贊 9 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章