使用類繼承還是類的成員變數
對於繼承和成員變數有很多相似的地方,那麼何時用繼續,何時用成員變數呢。是不是都用繼承好呢?
比如有個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 本文僅從使用的方面做了簡單的建議,還可以從類的構造和析構順序,儲存空間,生命週期等方面進行選擇。
相關文章
- 類&成員可見性&繼承繼承
- oop類的繼承與類靜態成員學習OOP繼承
- 18、繼承以及繼承中成員變數和成員方法的重名問題繼承變數
- 類的繼承_子類繼承父類繼承
- Java中變數之區域性變數、本類成員變數、父類成員變數的訪問方法Java變數
- 類成員變數的初始化變數
- Java基礎 成員變數的繼承與覆蓋Java變數繼承
- c#繼承父子類成員間的互訪問性C#繼承
- 子父類中成員變數變數
- 類的繼承繼承
- 類的繼承,介面的使用繼承
- python 類繼承,對類屬性的改變Python繼承
- C/C++—— 除了用類成員函式訪問類私有成員變數外,還可以通過類物件地址來直接訪問和修改類的私有成員變數C++函式變數物件
- javascript類繼承JavaScript繼承
- 類的成員變數的初始化順序變數
- 繼承 基類與派生類繼承
- PHP 抽象類繼承抽象類時的注意點PHP 抽象類繼承抽象類時的注意點PHP抽象繼承
- Java類是如何預設繼承Object的?Java繼承Object
- JS原型繼承和類式繼承JS原型繼承
- Python類的繼承Python繼承
- 類的繼承圖解繼承圖解
- Java的類與繼承Java繼承
- Swift—類的繼承-備Swift繼承
- 類的繼承和派生繼承
- Python中類變數、成員變數、區域性變數的區別Python變數
- API的使用(3)Arrays 類,Math類,三大特性--繼承API繼承
- 類的靜態成員變數和普通成員變數該怎樣去區別定義變數
- TypeScript 介面繼承類TypeScript繼承
- 原型繼承:子類原型繼承
- C++ | 類繼承C++繼承
- iOS 繼承&類方法iOS繼承
- Java:類與繼承Java繼承
- 通過反射獲取類的類名,方法和內部成員變數反射變數
- 類,物件,成員變數和區域性變數,匿名物件物件變數
- C# 繼承 子類(派生類) 父類(基類)C#繼承
- C++類的靜態成員變數初始化C++變數
- Python面試題1:類變數在繼承中的深入理解Python面試題變數繼承
- 繼承自NumberPicker的數字輸入類繼承