標籤:分類 int idt 問題 物件導向 類成員 char color 方法
2017-06-25 23:00:59
c++中的繼承和派生是物件導向編程中的一個重要內容,通過繼承可以實現代碼的複用,同時繼承也是實現多態性的基礎。
一、c++繼承的基本形式
class 衍生類別名:繼承方式 基類名,繼承方式 基類名
{};
繼承方式主要有三種,public ,private ,protected。
預設條件下是private繼承,三種中public繼承用的最多,不同的繼承方式決定了子類中從基類繼承過來的成員的訪問屬性。
public繼承:
基類的public,protected成員在子類中訪問屬性不變,子類新增的成員函數可以直接存取,對於基類的private成員依然是基類的私人,子類無法直接進行訪問。
private繼承:
基類的public,protected成員轉變為子類的private成員,子類新增的成員函數可以進行訪問,對於基類的private成員依然是基類的私人,子類無法直接進行訪問。
protected繼承:
基類的public,protected成員轉變為子類的protected成員,子類新增的成員函數可以進行訪問,對於基類的private成員依然是基類的私人,子類無法直接進行訪問。
private繼承和protected繼承的區別是private繼承的子類如果繼續被繼承,那麼這些從其分類繼承得到的資料將不會被其子類繼承,而protected則是可以的。
二、c++繼承的注意事項
(1)父類的建構函式和解構函式是不會被繼承的,需要重寫衍生類別的建構函式和解構函式。
衍生類別的成員資料中有來自父類的成員資料,因此在寫衍生類別的建構函式的時候需要調用其父類的建構函式。
如果衍生類別的成員中有成員對象,那麼也需要用成員對象名來進行初始化。
這兩種都是用初始化表來進行初始化工作的。
(2)衍生類別建構函式、解構函式的調用順序
- 建構函式中首先先調用各個直接基類的建構函式,之後再調用成員對象的建構函式,最後才是新增成員的初始化。
- 對於多繼承有多個基類,那麼其建構函式的調用順序是按被繼承時的聲明順序,從左至右一次調用,與初始化表的順序無關。
- 對於成員對象的初始化也是一樣,與他們的聲明順序有關,和建構函式中的初始化表的順序無關。
- 如果沒有進行顯示的調用,那麼會調用其預設的建構函式
- 子類的拷貝建構函式也要為各個直接基類的拷貝建構函式傳遞參數
//若 B 類是 C 類的基類,則 C 類的自訂拷貝建構函式可定義為:C:: C ( C &c1 ) : B ( c1 ) { 函數體 }
- 在衍生類別的解構函式中不會顯示調用基類的解構函式,系統會自動隱式調用,調用順序和建構函式的調用順序正好相反。先構造的後析構。
class A{ int x1,y1;public: //建構函式 A(int a=0,int b=0) { x1=a; y1=b; cout<<"調用A的建構函式了\n"; } //拷貝建構函式 A(A& a) { x1=a.x1; y1=a.y1; cout<<"調用A的拷貝建構函式了"<<endl; } //展示內容 void show() { cout<<x1<<" "<<y1<<endl; } //解構函式,解構函式無參數且無傳回值 ~A() { cout<<"調用A的解構函式了"<<endl; }};class B{ int x2,y2;public: //建構函式 B(int a=0,int b=0) { x2=a; y2=b; cout<<"調用B的建構函式了\n"; } //拷貝建構函式 B(B& b) { x2=b.x2; y2=b.y2; cout<<"調用B的拷貝建構函式了"<<endl; } //展示內容 void show() { cout<<x2<<" "<<y2<<endl; } //解構函式,解構函式無參數且無傳回值 ~B() { cout<<"調用B的解構函式了"<<endl; }};class C:public A,public B{ int x3,y3;public: //形參寫成int x3,int y3,也就是和成員函數重名的話,內部的資料會出錯,所以,不要重名,改成a,b即可 C(int x1,int y1,int x2,int y2,int a,int b):A(x1,y1),B(x2,y2) { x3=a; y3=b; cout<<"調用C的建構函式了"<<endl; } C(C& c):A(c),B(c) { x3=c.x3; y3=c.y3; cout<<"調用C的拷貝建構函式了"<<endl; } void show() { A::show(); B::show(); cout<<x3<<" "<<y3<<endl; } ~C() { cout<<"調用C的解構函式了"<<endl; }};int _tmain(int argc, _TCHAR* argv[]){ C c1(1,2,3,4,5,6); c1.show(); C c2(c1); c2.show(); return 0;}
(3)賦值相容規則
規定了基類和其子類之間的賦值規則。
對於公有派生,可以將衍生類別對象賦值給其基類,反之則是不被允許的。
具體體現為:
- 基類對象=衍生類別對象
- &基類對象的別名=衍生類別對象
- *基類對象的指標=&衍生類別對象的地址
對於這種賦值,基類只能訪問子類中從基類繼承過來的那部分成員。
(4)繼承過程中的二義性問題
繼承過程中可能會出現二義性的問題。主要有兩種形式的二義性。
一是在多繼承中,兩個父類中有同名的變數,這時如果是公有繼承,那麼子類中就會出現兩個同名變數。解決方案有兩種,一是用域作用符進行限定,二是使用同名隱藏。
二是在多繼承中,兩個父類的父類是同一個類,這時就需要使用虛基類的手段來進行解決。虛基類可以保證在間接繼承的時候只保留一份共同基類的成員資料。
虛基類的定義:
class 衍生類別:virtual 繼承方式 基類名
{};
- 由虛基類直接或者間接派生出來的子類都必須列出對虛基類的建構函式,若未顯示列出則調用預設建構函式
- 最終建立對象的類稱為最終衍生類別,只在最終衍生類別中調用基類的建構函式,而在基類的直接衍生類別中不掉用基類的建構函式,這樣就避免了基類成員的重複繼承問題
class B{ int b;public: B(int x) { b=x; cout<<"調用了B的建構函式"<<endl; } ~B() { cout<<"調用了B的解構函式"<<endl; }};class B1:virtual public B{ int b1;public: B1(int x,int y):B(x) { b1=y; cout<<"調用B1的建構函式了"<<endl; } ~B1() { cout<<"調用B1的解構函式了"<<endl; }};class B2:virtual public B{ int b2;public: B2(int x,int y):B(x) { b2=y; cout<<"調用B2的建構函式了"<<endl; } ~B2() { cout<<"調用B2的解構函式了"<<endl; }};class C:public B1,public B2{ int c;public: C(int a,int b,int c,int d):B1(a,b),B2(a,c),B(a) { c=d; cout<<"調用C的建構函式了"<<endl; } ~C() { cout<<"調用C的解構函式了"<<endl; }};int _tmain(int argc, _TCHAR* argv[]){ C c1(1,2,3,4); return 0;}
C++繼承與派生