條款32:確定你的public繼承塑模出is-a模型
? ? ? ?class D(derived)以public形式繼承class B(base),則每一個類型為D的對象同時也是一個類型為B的對象,反之不成立,因此B比D表現出更加一般化的概念,而D比B表現出更特殊化的概念。在C++領域里面,任何函數如果希望獲得一個類型為B的實參,都也愿意接受一個類型為D的對象,這就是is-a(是一種)的關系;代碼分享:
class ractangle{
public:
virtual void setheight(int newheight);
virtual void setwidth(int newwidth);
virtual int height( ) const;
virtual int width( ) const;
};
void makebigger(rectangle &r){
int oldheight=r.height( );
r.setwidth(r.width( )+10);
assert(r.height()==oldheight);//assert為真
}
class square:public rectangle{ ...};
square s;
assert(s.width()==s.height( ));//assert為真
makebiggle(s);
assert(s.width()==s.height( ));//asseert為真 ,為什么s沒有發生變化;
在本例分析中,某些可施行在矩形身上的事情(寬度可獨立于高度被修改)卻沒辦法施行在正方形身上(寬度和高度一樣),但public主張,能夠施行在base class對象上的每一件事情,都能施行于derived class對象上,所以正方形和矩形的例子中不滿足is-a模型;pulic就意味著is-a模型,因此在繼承中確定你的class之間的關系,并合理塑造它們;
條款33:避免遮掩繼承而來的名稱(繼承而導致的作用域問題)
? ? ? ? ? 在public繼承中,derived class中的成員函數會將base class中重名的成員函數覆蓋掉,從而出現因繼承導致成員函數調用問題;因此使用public繼承但又不繼承那些重載函數,這就違背了public繼承中的is-a原則;
? ? ? ? ?如果你想繼承base class并加上重載函數,而你希望重新定義或者復寫其中一部分,那么你必須為那些原本會被遮掩的每個名稱引用一個using的聲明,否則某些你希望繼承的名稱會被遮掩;
? ? ? ? ?如果derived以private方式繼承的base,如果使用using聲明,那么給定名稱的函數會在derived中都可見,這并不是我們希望達到的目的,這時候我們可以使用一個簡單的轉交函數;
class base{
public:
virtual void mf1()=0;
virtual void mf1(int);
...
};
class derived:private base {
public:
? virtual void mf1( ){//轉交函數
? ? ? ? base::mf1( );//inline函數
?}
};
條款34:區分接口繼承和實現繼承
? ? ? ? ? public繼承分為函數接口繼承和函數實現繼承;
? ? ? ? ? 1)對于pure virtual函數,它有兩個特性,它們必須被任何“繼承了它們”的具象class重新聲明,而且它們在抽象class中通常沒有定義,因此聲明一個pure virtual函數的目的是為了derived class只繼承接口(只具體接口繼承);
? ? ? ? ?引申:我們可以給pure virtual函數提供定義,也就是說你可以給base中的pure virtual函數提供一份實現代碼,C++并不會發出警告和錯誤,但調用它的唯一途徑就是:調用時明確指出其class路徑;(一直以為pure virtual函數不能在base內實現)
? ? ? ? ?2)derived class繼承函數接口,但是impure virtual函數會提供一份實現代碼,derived class可能會賦寫它;聲明簡樸的impure virtual 函數的目的,是讓derived classes繼承該函數的接口和缺省實現(具體指定接口繼承和缺省實現繼承);
? ? ? ? ?如果在繼承過程中,derived class中沒有重新定義virtual class,那么就默認使用base class中的virtual函數;如果兩個class都共享著一份相同的性質,可以把這份相同的性質搬到base class中,從而避免代碼重復,這是典型的面向對象的設計方法;
? ? ? ?3)對于一個non-virtual函數,意味著它并不打算在derived class中有不同的行為,實際上一個non-virtual成員函數所表現出來的不變性凌駕其特異性,因此不管derived class變得多特異化,它的行為都不可以被改變;聲明一個non-virtual函數的目的是為了令derived class繼承函數的接口及一份強制性的實現(具體指定接口及強制性實現繼承);