使用類繼承還是類的成員變數

軍說網事發表於2017-12-30

對於繼承和成員變數有很多相似的地方,那麼何時用繼續,何時用成員變數呢。是不是都用繼承好呢?

 

比如有個class A 和 class B
我在B裡面定義一個A型別成員 a;
class B
{
...
A a;
...
};

或者把A作為B的父類
class B : public A
{
};
又有個 B b;
要用a的時候兩種方法都可以通過 b.a 來做到。
那麼繼承的優點都體現在哪呢?

 

其實它們非常像,但是還是有些區別:

1 對於protected的成員變數的訪問
比如我要在B中訪問類A的一個成員變數m,通過繼承的方式只要在類A中把m宣告成protected,如果是包含的話,需要在類A中實現一個成員函式GetM返回m的值,如果要修改它的值同樣又要實現一個SetM成員函式
如果B還有子類,B的子類要訪問類A的成員變數,用包含的方式就更麻煩了。

2 對於容器裡存放類

B繼承A,表明B也是A的一種。
那麼B同時具備了A的所有virtual介面。
舉例:這時候A和B就可以混放到某個容器裡。比如std::vector<A>。
這裡面可以放A,也可以放B,然後再比如你for這個vector的時候就可以call到對應的virtual介面而不再需要型別判定。所謂多型(執行期)就是如此,面向介面的程式設計, Interface Oriented Programming。

至於B包含了A的做法,表明是:B使用了A。
就好比汽車有輪子,但汽車並不是輪子。
這時候std::vector<A>顯然不能再放B了,因為性質完全不同。

絕大多數複雜業務的軟體是兩者都要同時使用的,對於繼承則多數是繼承介面(virtual xxxx = 0;)
而不是繼承其實現。

此外,還有除了執行時動態多型,還有靜態多型,多數時候用模板實現。
多型並不是一個語言強相關概念,而是一個抽象概念,用於描述業務物件之間的共性等複雜關係。

 

3 繼承顯示多型的特性

繼承使得多型變成可能,讓基類的指標或引用繫結派生類,也就是如果B C D都有繼承A的的話,就可以A* ptrA=&B 或A* ptrA=&C之類去用基類指標指向派生類。這樣的好處是可以用同一份程式碼去訪問A擁有的介面。


而且如果A類有虛擬函式給B C D去過載的話,這樣用A*去訪問B C D中A部分的介面就可以實現“一個介面,多種策略”。因為用基類指標去這麼訪問介面用哪個版本,取決於這個指標繫結的物件。

 

比如資料庫操作,可以定義的一個基類或者介面類,提供給訪問資料庫的程式呼叫,但是他們並不用關心內部是如何實現的。而具體的資料庫可以通過特定的繼承類來實現。

 

4 繼承的優點是
1)擴大類的使用範圍,更便於使用類庫。
2)避免重寫程式程式碼,提供有用的概念框架。
3把類轉化成有條理的層次結構。

 

5 如何選擇和使用繼承

我們兩種方式的區別和繼承的優點,那麼何時用成員變數,何時用繼承呢。

個人覺得:

1)基礎的功能類,比如字串操作類,檔案處理類等功能比較單一的基礎類,建議直接使用成員變數。

2)有明顯的包含關係,比如說B類就是A類的一個具體的實現,用繼承。

3)需要對外部提供使用介面,不管是虛擬函式,還是介面函式,使用繼承,方便擴充套件和使用。

 

6 本文僅從使用的方面做了簡單的建議,還可以從類的構造和析構順序,儲存空間,生命週期等方面進行選擇。

相關文章