歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C++繼承與派生(原理歸納)

C++繼承與派生(原理歸納)

日期:2017/3/1 9:30:35   编辑:Linux編程

1. C++繼承與java不同,java遵循單繼承,但java的接口為其不足做了很好的彌補了。 C++則是靈活的多,為多繼承。即一個C++類可以同時繼承N個類的屬性。

2. 對於繼承方式 :

有三種: public ,private,protect,對於public繼承的類,其公有成員依然是公有成員,私有成員依舊是私有成員。

對於protect,private 則有限制 ,就好比一個水管,公有水管是最大號的,對於水的流量沒有限制。保護水管,是中等的號的,對於大號水管的流量使其變成中等流量,對於中等以下的不限制。私有水管,則是最小號的,對於大於私有水管限制的統統的改為私有水管的標准。 其中私有繼承,其實就是一種絕育的措施。就是以後的繼承就沒有太大意義。

3.對於繼承關於構造和析構順序原裡的歸納:

看代碼:

#include<iostream>
using namespace std ;

class Base1 {

public :
Base1() {
cout << "Default Base1" << endl;
}
Base1(int i) {
cout << "Base1"<<i<< endl;
}
~Base1() {
cout << "Base1 析構" << endl;
}
};

class Base2 {

public :
Base2() {
cout << "Default Base2" << endl;
}
~Base2() {
cout << "Base2 析構" << endl;
}
Base2(int i) {
cout << "Base2" << i << endl;
}
};
class Base3 {

public :
Base3() {
cout << "Default Base3" << endl;
}
~Base3() {
cout << "Base3 析構" << endl;
}
Base3(int i) {
cout << "Base3" << i << endl;
}

};


class Derived : public Base1, public Base2, public Base3 //(1)先 在這兒開始構造從左到右
//析構則是從右到左
{

public :
Derived() {
cout << "Default Derived" << endl;
}
~Derived() {
cout << "Derived 析構" << endl;
}
Derived( int a , int b , int c , int d )
:men2(b),Base1(a),Base3(c), Base2(d),men1(b) {
cout << "Derived" << endl;
};

private :
//構造從左到右
Base3 men3;
Base2 men2;
Base1 men1;

//析構則是從底部開始往上析構,先 Base 1,2,3
};

int main(void ) {

Derived obj(1,2,3,4);
return 0;

}

結果:

Base11
Base24
Base33
Default Base3
Base22
Base12
Derived
Derived 析構
Base1 析構
Base2 析構
Base3 析構
Base3 析構
Base2 析構
Base1 析構
請按任意鍵繼續. . .

4. 以上是對於單繼承的描述,如果是多繼承,那麼常規的話,我們很容易清楚器執行順序,但是如果是虛繼承,其執行順序又會如何 ?

1. 現在我們來看這樣一個圖:它的運行結果又是如何.......

#include<iostream>
using namespace std;

class Boss {

public :
Boss() {
cout << "this is Boss's constructor !" << endl;
};
Boss(int i) {
cout << "this is Boss's constructor !" \
<< " moneny=" << i << endl;
}

void show() {
cout<<"寶劍磨砺,斬魂妖,時光磨砂,魔刃出"<<endl;
}
virtual ~ Boss() {
cout << "this is Boss's xigou function !" << endl;
}; //虛析構函數
};

//店小二
class xiao_er :virtual public Boss
{
public:
xiao_er() {
cout << "this is xiao_er's constructor !"<<endl;
}
xiao_er(int i) : Boss(i){
cout << "this is xiao_er's constructor !" \
<< " moneny=" << i << endl;
}
virtual ~xiao_er() {
cout << "this is xiao_er's xigou function !" << endl;
}
void show() {
cout << "我是店小二,客官 !" << endl;
}
};

//王二小
class er_xiao : virtual public Boss \
, virtual public xiao_er /*其實這裡這個可以省去,但是這兒是為了寫代碼而寫代碼*/
{
public :
er_xiao() {
cout << "this is er_xiao's constructor !" << endl;
}
er_xiao(int i) : \
Boss(i) , xiao_er(i+1)
{
cout << "this is er_xiao's constructor !" \
<< " moneny=" << i << endl;
}
virtual ~ er_xiao() {
cout << "this is er_xiao's xigou function !"<<endl;
}
void show() {
cout << "我是王二小,為壞人帶路的王二小 !" << endl;
}
};

//天朝VIP員工
class VIP_em : virtual public Boss
{

public:
VIP_em(){
cout << "this is VIP_em's constructor !" << endl;
}

VIP_em(int i) : \
Boss(i)
{
cout << "this is VIP_em's constructor !" \
<< " moneny=" << i << endl;
}
virtual ~VIP_em() {
cout << "this is VIP_em's xigou function !" << endl;
}
void show() {
cout << "我是VIP , 我有特權! "<<endl;
}
};

//熊孩子
class stupid_kid : virtual public VIP_em \
, virtual public xiao_er , \
virtual public er_xiao
{
public:
stupid_kid() {
cout << "this is stupid_kid's constructor !" << endl;
}

stupid_kid(int i) : \
VIP_em(i) , xiao_er(12) , er_xiao(13),xe(i)
{
cout << "this is stupid_kid's constructor !" \
<<" moneny="<<i<<endl;
}
~stupid_kid() {
cout << "this is stupid_kid's xigou function !"<<endl;
}

void show() {
cout << "我是熊孩子,蜀黍,蜀黍,抱抱!" << endl;
}
private :
VIP_em vi;
xiao_er xe;
er_xiao ex;
};

int main(){

stupid_kid st(100);
//父類的函數被覆蓋了
st.show();
//如何調用父類,強制是一種。
((Boss)st).show();

//stupid_kid *pt = &st;
//stupid_kid &sb = st;
// pt->show();
//((Boss)sb).show();
return 0;
}


結果為:

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指針指著同一個地址時,就不重復構造。 其他的,構造函數和析構函數,基於第一個代碼列子。 根據自己對源碼的理解和測試的總結,如有錯誤,還請多多指正。

編程是一種快樂,享受代碼帶給我的樂趣!!!

Copyright © Linux教程網 All Rights Reserved