//#32 確定你的public繼承塑膜出 is-a 關系
{
/*
1>子類is-a父類。
如果以public形式繼承,你便是告訴c++編譯器說,每一個類型為子類的對象同時也是一個父類的對象。
也就是父類表現出更一般化的概念。
2>只要是父類能用到的地方,子類也一定能有用,但是如果什麼地方子類能用,父類就不一定能用了。
3>is-a的困惑點:
1)bird能飛,企鵝是bird,所以也能飛:
這裡首先bird並不是都能飛的,所以這裡應該分類成flybird和notflybird。企鵝就能繼承
notflybird了。
然而有些系統並不會用到企鵝,而且能飛的bird還是很多的,所以可以適當考慮不去區分能不能飛
也就是學會靈活變通。
2)正方形是一個矩形:
矩形調整長度的時候,寬度是不會變的,但是正方形調整長度的時候,寬度要跟著變化。
所以解決辦法是改寫正方形的SetWidth和SetHeight,讓這兩個函數在改動一個時,另一個跟著變。
畢竟正方形是一個特殊的長方形,你要改變我的長,ok,寬度也必須跟著變。
*/
}
//#33 避免遮掩繼承而來的名稱
{
// 先看看下面的代碼:
class Base
{
public:
virtual void mf1();
virtual void mf1(int);
virtual void mf3();
virtual void mf3(int);
};
class Derived : public base
{
virtual void mf1();//並沒有定義mf1(int),所以基類的mf1(int)就被遮蓋了。
using Base::mf1; //這樣才能讓mf1(int)被看見。
virtual void mf3()
{
Base::mf3(); //!!!!!如果是private繼承!!!!!!!(不是private繼承就不要這麼做),這麼做
//可以故意遮蓋基類的mf3(int),只留下基類的mf3()
}
};
}
//#34 區分接口繼承和實現繼承
{
/*
1:子類繼承接口總是有三種情況:
1>只繼承函數接口,不繼承實現:pure virtual函數能實現這樣的功能。
2>繼承接口和缺失實現: impure virtual函數。這時會有可能造成危險情況。因為這個接口沒有要求客戶強制
實現,所以如果在有必要的情況下,客戶卻沒有實現,則會造成錯誤。
解決辦法就是:基類提供一個缺失實現的成員函數,子類繼承接口的時候,如果想要缺省實現,直接調用基類
提供的成員函數就行。這時接口聲明成pure virtual的,子類就必須重新實現,至於要不要缺省情況,就看子類
自己調不調用了。
3>繼承接口和強制性實現(不允許修改),non_virtual函數。聲明為non_virtual意味著基類不想子類重定義這個
接口。
2:錯誤情況:
1>全部實現為non_virtual函數,這一的設計使得子類無法定制自己的情況。而且析構函數必須是virtual的(如
果你想讓這個類作為基類的話)
2>全部實現為virtual,例外:interface classes,除了這個類接口,其他的類不應該把接口全設置為virtual
因為這可能是class設計者缺乏堅定立場的前兆。某些函數就是不該被重定義的!
*/
}