一、父類與子類1.父類與子類的相互轉換
衍生類別的對象可以賦給基類,反之不行
基類的指標可以指向衍生類別,反之不行
基類的引用可以初始化為衍生類別的對象,反之不行
衍生類別指標必須強制轉換為基類指標後才可以指向基類
基類指標轉換為衍生類別指標容易導致崩潰性錯誤
虛基類的引用或派生不能轉換為衍生類別
class father{};class son:public father{};int main(){father f;son s;f = s;//正確s = f;//錯誤father *pf = new son;//正確son *ps = new father;//錯誤father &rf = s;//正確father &rs = f;//錯誤return 0;}
2.繼承關係對基類成員的影響
| |
公有成員 |
保護成員 |
私人成員 |
| 公有繼承 |
公有 |
保護 |
不可訪問 |
| 保護繼承 |
保護 |
保護 |
不可訪問 |
| 私人繼承 |
私人 |
私人 |
不可訪問 |
| 成員函數 |
1 |
1 |
1 |
| 對象 |
1 |
0 |
0 |
| 子類 |
1 |
1 |
0 |
1:可以訪問 0:不可訪問
當所有成員都變成不可訪問時,再往下派生就沒有意義了二、子類的構造與析構1.構造衍生類別對象時,先執行基類的建構函式,再執行子類的建構函式,析構反之
class father{public:father(){cout<<"father construct"<<endl;}~father(){cout<<"father delete"<<endl;}};class son : public father{public:son(){cout<<"son construct"<<endl;}~son(){cout<<"son delete"<<endl;}};int main(){son s;return 0;}
輸出:
father construct
son construct
son delete
father delete
2.如果是多重繼承,基類的構造順序按給定的順序,析構反之
class father{public:father(){cout<<"father construct"<<endl;}~father(){cout<<"father delete"<<endl;}};class mother{public:mother(){cout<<"mother construct"<<endl;}~mother(){cout<<"mother delete"<<endl;}};class son : public father, public mother{public:son(){cout<<"son construct"<<endl;}~son(){cout<<"son delete"<<endl;}};int main(){son s;return 0;}
輸出:
father construct
mother construct
son construct
son delete
mother delete
father delete
3.利用基類的建構函式構造子類,效率更高
class father{int x;public:father(int a):x(a){cout<<"father construct:"<<x<<endl;}};class son : public father{int y;public:son(int a, int b):father(a), y(b){cout<<"son construct:"<<y<<endl;}};int main(){son s(1, 2);return 0;}
輸出:
father construct:1
son construct:2
三、多重繼承
1.多重繼續的二義性,根本原因是
假如A有Test(),則B和C都有Test(),於是D產生了二義性
class A{public:void Test(){cout<<"A"<<endl;}};class B{public:void Test(){cout<<"B"<<endl;}};class C : public A, public B{};int main(){C c; c.Test(); //錯誤c.A::Test(); //正確,輸出:Ac.B::Test(); //正確,輸出:Breturn 0;}
2.編譯器通常都是從離自己最近的分類樹向上搜尋的
子類的Test()覆蓋了基類的Test(),並不代表基類的Test()消失,只是不能直接存取
class A{public:void Test(){cout<<"A"<<endl;}};class B{public:void Test(){cout<<"B"<<endl;}};class C : public A, public B{void Test(){cout<<"C"<<endl;}};int main(){C c; c.Test(); //正確,輸出:Cc.A::Test(); //正確,輸出:Ac.B::Test(); //正確,輸出:Breturn 0;}
3.對於單一繼承,子類能否訪問父類的父類,只與繼承的方式有關
對於多重繼承,子類不能直接存取父類的父類。
4.用virtual來避免二義性。
class B : virtual public A.
四、繼承與包含1.一個類的成員變數列表中包含另一個類的對象,叫做包含(包容)。2.包含與私人繼承的區別:
包含:
1)使程式看上去更清晰易懂
2)不存在繼承帶來的問題
3)可以包括另一個類的多個對象
私人繼承:
1)可以訪問基類的保護成員
2)可以重定義虛函數,實現多態