C++繼承與派生(原理歸納)
1. C++繼承與java不同,java遵循單繼承,但java的接口為其不足做了很好的彌補了。 C++則是靈活的多,為多繼承。即一個C++類可以同時繼承N個類的屬性。
2. 對於繼承方式 :
有三種: public ,private,protect,對於public繼承的類,其公有成員依然是公有成員,私有成員依舊是私有成員。
對於protect,private 則有限制 ,就好比一個水管,公有水管是最大號的,對於水的流量沒有限制。保護水管,是中等的號的,對於大號水管的流量使其變成中等流量,對於中等以下的不限制。私有水管,則是最小號的,對於大於私有水管限制的統統的改為私有水管的標准。 其中私有繼承,其實就是一種絕育的措施。就是以後的繼承就沒有太大意義。
3.對於繼承關於構造和析構順序原裡的歸納:
看代碼:
1 #include<iostream>
2 using namespace std ;
3
4 class Base1 {
5
6 public :
7 Base1() {
8 cout << "Default Base1" << endl;
9 }
10 Base1(int i) {
11 cout << "Base1"<<i<< endl;
12 }
13 ~Base1() {
14 cout << "Base1 析構" << endl;
15 }
16 };
17
18 class Base2 {
19
20 public :
21 Base2() {
22 cout << "Default Base2" << endl;
23 }
24 ~Base2() {
25 cout << "Base2 析構" << endl;
26 }
27 Base2(int i) {
28 cout << "Base2" << i << endl;
29 }
30 };
31 class Base3 {
32
33 public :
34 Base3() {
35 cout << "Default Base3" << endl;
36 }
37 ~Base3() {
38 cout << "Base3 析構" << endl;
39 }
40 Base3(int i) {
41 cout << "Base3" << i << endl;
42 }
43
44 };
45
46
47 class Derived : public Base1, public Base2, public Base3 //(1)先 在這兒開始構造從左到右
48 //析構則是從右到左
49 {
50
51 public :
52 Derived() {
53 cout << "Default Derived" << endl;
54 }
55 ~Derived() {
56 cout << "Derived 析構" << endl;
57 }
58 Derived( int a , int b , int c , int d )
59 :men2(b),Base1(a),Base3(c), Base2(d),men1(b) {
60 cout << "Derived" << endl;
61 };
62
63 private :
64 //構造從左到右
65 Base3 men3;
66 Base2 men2;
67 Base1 men1;
68
69 //析構則是從底部開始往上析構,先 Base 1,2,3
70 };
71
72 int main(void ) {
73
74 Derived obj(1,2,3,4);
75 return 0;
76
77 }
Base11
Base24
Base33
Default Base3
Base22
Base12
Derived
Derived 析構
Base1 析構
Base2 析構
Base3 析構
Base3 析構
Base2 析構
Base1 析構
請按任意鍵繼續. . .
4. 以上是對於單繼承的描述,如果是多繼承,那麼常規的話,我們很容易清楚器執行順序,但是如果是虛繼承,其執行順序又會如何 ?
1. 現在我們來看這樣一個圖:它的運行結果又是如何.......
1 #include<iostream>
2 using namespace std;
3
4 class Boss {
5
6 public :
7 Boss() {
8 cout << "this is Boss's constructor !" << endl;
9 };
10 Boss(int i) {
11 cout << "this is Boss's constructor !" \
12 << " moneny=" << i << endl;
13 }
14
15 void show() {
16 cout<<"寶劍磨砺,斬魂妖,時光磨砂,魔刃出"<<endl;
17 }
18 virtual ~ Boss() {
19 cout << "this is Boss's xigou function !" << endl;
20 }; //虛析構函數
21 };
22
23 //店小二
24 class xiao_er :virtual public Boss
25 {
26 public:
27 xiao_er() {
28 cout << "this is xiao_er's constructor !"<<endl;
29 }
30 xiao_er(int i) : Boss(i){
31 cout << "this is xiao_er's constructor !" \
32 << " moneny=" << i << endl;
33 }
34 virtual ~xiao_er() {
35 cout << "this is xiao_er's xigou function !" << endl;
36 }
37 void show() {
38 cout << "我是店小二,客官 !" << endl;
39 }
40 };
41
42 //王二小
43 class er_xiao : virtual public Boss \
44 , virtual public xiao_er /*其實這裡這個可以省去,但是這兒是為了寫代碼而寫代碼*/
45 {
46 public :
47 er_xiao() {
48 cout << "this is er_xiao's constructor !" << endl;
49 }
50 er_xiao(int i) : \
51 Boss(i) , xiao_er(i+1)
52 {
53 cout << "this is er_xiao's constructor !" \
54 << " moneny=" << i << endl;
55 }
56 virtual ~ er_xiao() {
57 cout << "this is er_xiao's xigou function !"<<endl;
58 }
59 void show() {
60 cout << "我是王二小,為壞人帶路的王二小 !" << endl;
61 }
62 };
63
64 //天朝VIP員工
65 class VIP_em : virtual public Boss
66 {
67
68 public:
69 VIP_em(){
70 cout << "this is VIP_em's constructor !" << endl;
71 }
72
73 VIP_em(int i) : \
74 Boss(i)
75 {
76 cout << "this is VIP_em's constructor !" \
77 << " moneny=" << i << endl;
78 }
79 virtual ~VIP_em() {
80 cout << "this is VIP_em's xigou function !" << endl;
81 }
82 void show() {
83 cout << "我是VIP , 我有特權! "<<endl;
84 }
85 };
86
87 //熊孩子
88 class stupid_kid : virtual public V
, virtual public xiao_er , \
90 virtual public er_xiao
91 {
92 public:
93 stupid_kid() {
94 cout << "this is stupid_kid's constructor !" << endl;
95 }
96
97 stupid_kid(int i) : \
98 VIP_em(i) , xiao_er(12) , er_xiao(13),xe(i)
99 {
100 cout << "this is stupid_kid's constructor !" \
101 <<" moneny="<<i<<endl;
102 }
103 ~stupid_kid() {
104 cout << "this is stupid_kid's xigou function !"<<endl;
105 }
106
107 void show() {
108 cout << "我是熊孩子,蜀黍,蜀黍,抱抱!" << endl;
109 }
110 private :
111 VIP_em vi;
112 xiao_er xe;
113 er_xiao ex;
114 };
115
116 int main(){
117
118 stupid_kid st(100);
119 //父類的函數被覆蓋了
120 st.show();
121 //如何調用父類,強制是一種。
122 ((Boss)st).show();
123
124 //stupid_kid *pt = &st;
125 //stupid_kid &sb = st;
126 // pt->show();
127 //((Boss)sb).show();
128 return 0;
129 }
結果為:
this is Boss's constructor !
this is VIP_em's constructor ! moneny=100
this is xiao_er's constructor ! moneny=12
this is er_xiao's constructor ! moneny=13
-------------這部分為熊孩子的繼承部分構造函數
下面是私有變量的構造函數
this is Boss's constructor !
this is VIP_em's constructor !
------私有變量 Vip_em調用無參數的構造函數
this is Boss's constructor ! moneny=100
this is xiao_er's constructor ! moneny=100
------私有變量 xiao_er調用有參數的構造函數
this is Boss's constructor !
this is xiao_er's constructor !
------私有變量 xiao_er調用無參數的構造函數
this is er_xiao's constructor !
this is stupid_kid's constructor ! moneny=100
我是熊孩子,蜀黍,蜀黍,抱抱!
寶劍磨砺,斬魂妖,時光磨砂,魔刃出
this is Boss's xigou function !
this is stupid_kid's xigou function !
this is er_xiao's xigou function !
this is xiao_er's xigou function !
this is Boss's xigou function !
this is xiao_er's xigou function !
this is Boss's xigou function !
this is VIP_em's xigou function !
this is Boss's xigou function !
this is er_xiao's xigou function !
this is xiao_er's xigou function !
this is VIP_em's xigou function !
this is Boss's xigou function !
請按任意鍵繼續. . .
6、 從上述代碼可以不難看出, 虛內繼承,避免了二義性,僅僅壓縮了公有的你虛類繼承類。
如果要弄清楚虛擬繼承,就得先知道virtual table (vtbl) ----我們說的虛函數表
在內存那塊, 會留 下一塊連續的內存塊,用作vtble存儲JMP地址,而vtble裡頭存的便是virtual function(虛函數)地址,
每次繼承時,基類都會產生一個vptr指針,指向派生類的地質,當 vptr指針指著同一個地址時,就不重復構造。 其他的,構造函數和析構函數,基於第一個代碼列子。 根據自己對源碼的理解和測試的總結,如有錯誤,還請多多指正。