條款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()被遮掩了