技術交流QQ群:1027579432,歡迎你的加入!
1.Cpp中的繼承
- 面向對象程序設計中最重要的一個概念是繼承。繼承允許我們依據(jù)另一個類來定義一個類,這使得創(chuàng)建和維護一個應用程序變得更容易。這樣做,也達到了重用代碼功能和提高執(zhí)行時間的效果。當創(chuàng)建一個類時,您不需要重新編寫新的數(shù)據(jù)成員和成員函數(shù),只需指定新建的類繼承了一個已有的類的成員即可,這個已有的類稱為基類,新建的類稱為派生類。繼承代表了is a關系。例如,哺乳動物是動物,狗是哺乳動物。因此,狗是動物。
2.基類&派生類
-
一個類可以派生自多個類,這意味著,它可以從多個基類繼承數(shù)據(jù)和函數(shù)。定義一個派生類,我們使用一個類派生列表來指定基類。類派生列表以一個或多個基類命名,形式如下:
class derived-class: access-specifier base-class- 訪問修飾符access-specifier: public、protected 或 private 其中的一個,默認是private
- base-class: 基類的名字
- derived-class: 派生類的名字
- 繼承的實例如下:
#include "iostream" using namespace std; class Shape{ public: void setWidth(int w){ width = w; } void setHeight(int h){ height = h; } protected: int width; int height; }; class Rect: public Shape{ public: int getArea(){ return width * height; } }; int main(){ Rect r1; r1.setWidth(3); r1.setHeight(4); cout << "r1對象的面積是: " << r1.getArea() << endl; return 0; }
3.訪問控制和繼承
-
派生類可以訪問基類中所有的非私有成員。因此基類成員如果不想被派生類的成員函數(shù)訪問,則應在基類中聲明為private??梢愿鶕?jù)訪問權限總結出不同的訪問類型,如下所示:
訪問控制和繼承.png - 一個派生類繼承了所有的基類方法,但下列情況除外:
- 基類的構造函數(shù)、析構函數(shù)和拷貝構造函數(shù);
- 基類的重載運算符;
- 基類的友元函數(shù).
4.繼承類型
- 當一個類派生自基類,該基類可以被繼承為public、protected或private幾種類型。繼承類型是通過上面講解的訪問修飾符 access-specifier來指定的。幾乎不使用protected或private繼承,通常使用public繼承。當使用不同類型的繼承時,遵循以下幾個規(guī)則:
- 公有繼承(public):基類中所有 public 成員在派生類中為 public 屬性;基類中所有 protected 成員在派生類中為 protected 屬性;基類中所有 private 成員在派生類中不能使用。基類的私有成員不能直接被派生類訪問,但是可以通過調用基類的公有和保護成員來訪問。
- 保護繼承(protected):基類中的所有 public 成員在派生類中為 protected 屬性;基類中的所有 protected 成員在派生類中為 protected 屬性;基類中的所有 private 成員在派生類中不能使用。
- 私有繼承(private):基類中的所有 public 成員在派生類中均為 private 屬性;基類中的所有 protected 成員在派生類中均為 private 屬性;基類中的所有 private 成員在派生類中不能使用。
- 基類的 private 成員不能在派生類中使用,并沒有說基類的 private 成員不能被繼承。實際上,基類的 private 成員是能夠被繼承的,并且(成員變量)會占用派生類對象的內存,它只是在派生類中不可見,導致無法使用罷了。private 成員的這種特性,能夠很好的對派生類隱藏基類的實現(xiàn),以體現(xiàn)面向對象的封裝性。
- 使用 using 關鍵字可以改變基類成員在派生類中的訪問權限,例如將 public 改為 private、將 protected 改為 public。using 只能改變基類中 public 和 protected 成員的訪問權限,不能改變 private 成員的訪問權限,因為基類中 private 成員在派生類中是不可見的,根本不能使用,所以基類中的 private 成員在派生類中無論如何都不能訪問。
5.多繼承
- 多繼承即一個派生類可以有多個基類,它繼承了多個基類的特性,C++類可以從多個類繼承成員,語法如下:
class 派生類名:繼承方式1 基類名1, 繼承方式2,基類名2,.....{ 派生類的主體 }; - 其中,訪問修飾符繼承方式是public、protected 或 private其中的一個,用來修飾每個基類,各個基類之間用逗號分隔,實例如下:
// 多繼承 class Shape{ public: void setWidth(int w){ width = w; } void setHeight(int h){ height = h; } protected: int width; int height; }; class Rect: public Shape{ public: int getArea(){ return width * height; } }; class PaintCost{ public: int getCost(int area){ return area * 66; } }; class D: public Shape, public PaintCost{ public: int getArea(){ return width * height; } }; int main(){ D d; int area; d.setWidth(4); d.setHeight(5); area = d.getArea(); cout << "總面積是: " << d.getArea() << endl; cout << "總代價是: " << d.getCost(area) << endl; return 0; } - 環(huán)狀繼承,如A->D,B->D,C->(A,B),如下所示:
class D{.....}; class A: public D{......}; class B: public D{......}; class C: public A, public B{.....}; - 上面的繼承方法會使D創(chuàng)建兩個對象,要解決上面問題就要用虛擬繼承格式,格式是: class 派生類名: virtual 繼承方式 基類名
class D{.....}; class A: virtual public D{......}; class B: virtual public D{......}; class C: public A, public B{......}; - 虛繼承: 在創(chuàng)建父類對象的時候會創(chuàng)建一個虛表,實例如下:
// 虛繼承 class D{ public: D(){ cout << "D對象的構造函數(shù)\n"; } ~D(){ cout << "D對象的析構函數(shù)\n"; } protected: int d; }; class B: virtual public D{ public: B(){ cout << "B對象的構造函數(shù)\n"; } ~B(){ cout << "B對象的析構函數(shù)\n"; } protected: int b; }; class A: virtual public D{ public: A(){ cout << "A對象的構造函數(shù)\n"; } ~A(){ cout << "A對象的析構函數(shù)\n"; } protected: int a; }; class C: public A, public B{ public: C(){ cout << "C對象的構造函數(shù)\n"; } ~C(){ cout << "C對象的析構函數(shù)\n"; } protected: int c; }; int main(){ C c; // D B A C cout << "sizeof(c) = " << sizeof(c) << endl; return 0; }
6.繼承中注意的知識點
- 派生類構造函數(shù)的調用順序:
- 基類的構造函數(shù)
- 子對象類的構造函數(shù)
- 派生類的構造函數(shù)
- 派生類的構造函數(shù)的初始化列表中,可以包含:
- 基類的構造函數(shù)
- 派生類中子對象的初始化
- 派生類中一般數(shù)據(jù)成員的初始化
- 解釋:派生類中的基類子對象和子對象必須初始化,初始化在派生類的構造函數(shù)的初始化列表中,如果初始化列表中沒有進行初始化,則調用缺省的構造函數(shù)進行初始化?;愖訉ο蟪跏蓟瘧撛诨惖臉嬙旌瘮?shù)中完成
