繼承
繼承允許我們一句另一個類來定義一個類,這使得繼承和維護一個程序變得更加容易,也達到了重用代碼功能和提高執行效率的效果。
一般格式為:
class 派生類名 :訪問修飾符 基類名{};
其中訪問修飾符是public protected private
中的一個,默認為private
派生類可以訪問基類中所有的非私有成員,因此基類成員如果不想被派生類的成員訪問,則應該在基類聲明為private
一個派生類繼承了所有的基類非私有方法,但是下列情況除外:
- 基類的構造函數,析構函數和拷貝構造函數
- 基類的重載運算符
- 基類的友元函數
繼承類型
- 公有繼承:基類的公有成員也是派生類的公有成員,基類的保護成員也是派生類的保護乘員胡安,基類的私有成員不能直接被派生類訪問,但是可以通過基類的公有和保護方法來訪問。
- 保護繼承:基類的公有和保護成員將成為派生類的保護成員
- 私有繼承:公有和保護成員將稱為派生類的私有成員
多繼承
一個子類可以有多個父類,繼承了多個父類的特性,不同父類用逗號隔開。
class <派生類名>:<繼承方式><基類名>,<繼承方式>,<基類名><繼承方式><基類名>,..
{};
虛繼承
因為C++多繼承的特性,當從兩個方向繼承到同一個類的時候就可能會出現拷貝了兩份相同數據的問題,這個時候訪問被拷貝多份的數據成員如果沒有加名字空間編譯器就會報錯,因為不確定到底訪問的是哪一份變量。為了解決這個問題,我們要使用虛繼承從而實現只拷貝一份變量。需要注意的一點是,虛繼承是指對多個類繼承一個類的時候需要進行虛繼承,這樣就能解決一個類繼承這多個類的時候出現的成員重復。
具體見樣例:
class A{};
class B:virtual public A{};
class C:virtual public A{};
class D:public B,public C{};//注意對D來講用virtual已經晚了,我們在上面個多個類繼承A的時候用虛繼承,這樣有其他類繼承B,C等的時候就不會出現問題。
繼承機理
編譯器先通過基類的構造函數創建一個基類的對象,然后再通過派生類的構造函數在后面加上派生類的成員,并進行初始化。基類中私有成員對派生類不可見,但是派生類對象可以通過父類提供的接口對父類中的對象進行訪問。實際上派生類成員是含有基類中的所有的成員的。
對于相同名字的數據成員,通過基類方法改變的是基類的數據成員,通過派生類方法改變的是派生類數據成員。如果想要訪問基類的(公有)成員可以使用名字空間。
可以由以下測試看出:
#include<iostream>
#include<cstdio>using namespace std;class A
{int a[100];
public:int b;
};
class B :public A
{//int c[50];int d;
};int main()
{B a;printf("%d", sizeof(a));return 0;
}
運行結果:
顯然派生類中含有基類的私有成員,只是不可以直接訪問。
派生類的構造函數
詳見另一篇文章:構造函數,作者講的很好。
在每次派生類構造函數調用時,首先會調用父類的構造函數,然后再調用派生類的構造函數,最后先調用派生類的析構函數,最后調用父類的析構函數。
在每個派生類構造函數中,如果我們要使用父類的有參構造函數,則需要在函數頭部調用。如果我們沒有顯式地調用父類的構造函數則編譯器會自動在派生類構造函數開頭調用基類的無參構造函數。(如果基類只有有參構造函數編譯器會因為找不到無參構造函數而報錯)。
顯式調用的格式如下:
class A
{public:A(int x){}
};
class B:public A
{
public:
B():A(x)//只可以在這一個地方顯式調用
{}
};
在其他地方顯式調用都是沒有意義的。(相當于創建了一個沒有辦法引用的父類)
見下例:
#include<iostream>
#include<cstdio>using namespace std;class A
{int a[100];
public:A(){printf("調用了無參構造函數\n");}~A(){printf("調用了析構函數\n");}A(int x){printf("調用了有參構造函數\n");a[0] = x;}int b;
};
class B :public A
{//int c[50];int d;
public:B(){A(5);printf("test\n");d = 0;}void Print(){printf("Hello world!\n");}
};int main()
{B* a=new B();printf("%d\n", sizeof(a));a->Print();delete a;return 0;
}
運行結果: