程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++裡的繼承和多態(下)——單繼承、多繼承、菱形繼承(含虛擬函數的繼承)

C++裡的繼承和多態(下)——單繼承、多繼承、菱形繼承(含虛擬函數的繼承)

編輯:關於C++

1、帶有虛函數的類

class Base
{
public:
                 virtual void FunTest1()
                {
                                cout << "Base::FunTest1()" << endl;
                }

                 virtual void FunTest2()
                {
                                cout << "Base::FunTest2()" << endl;
                }

                 int _data1;
};
int main()
{
                 Base b;
                b._data1 = 0x01;
                 return 0;
}


 

對象模型:

wKioL1cPn_yi_03PAAA2JVUVCGA101.png

wKioL1cPn_ygrPR1AAAMgfdfR08999.png

mian函數的反匯編:

如果類中沒有自己寫構造函數,並且含有虛函數,那麼編譯器就會合成一個缺省的構造函數。

wKiom1cPn0TSpo6VAABQjroo-Ag162.png

 

Base()的構造函數分析:

1>在它的構造函數中主要完成的是:在&b指向的那塊空間中,填寫了虛指針,

2>注意:虛表是編譯器在編譯和鏈接完成之後就已經建立好的,在構造函數中只是將虛表的地址填寫到對象的前4個字節。

3>虛表中虛函數地址的存放順序,是按照它在類中聲明的順序存放的。

4>虛表中最後的00 00 00 00 表示虛表結束(編譯器不同就不一定了)

wKiom1cPn5nT6VzKAAAInBJ_kDE706.png

vptr指向虛表:

wKioL1cPoFGCpyJwAAAF3tQbDdQ324.png

對象模型:

先是虛函數指針,再是該類的數據成員

wKioL1cPoFLQpwdFAAAfflnNSzQ826.png

 

 

 

2、單繼承(派生類中沒有虛函數的覆蓋)

class Base
{
public:
     virtual void FunTest1()
        {cout<<"Base::FunTest1()"<

 

主要還是完成虛指針的填寫

wKioL1cPoNfyDA5RAABWdv8yluE050.png

wKiom1cPoB-AwSDKAAAlxWWZhBk950.png

在是Derive的構造函數:

派生類最後的對象模型為:如果派生類沒有對基類中的虛函數進行重寫時,派生類中的虛表先是基類的虛函數地址,然後再加上自己的虛函數地址。虛函數地址的順序為在類中聲明的順序。

wKioL1cPoNeS9cE0AAAjNGN9VEE508.png

wKiom1cPoB-gdKUDAAAQPHOzjnY387.png

派生類中Base的虛表

wKioL1cPoNiAsEoVAAA7IXYhCq8794.png

wKiom1cPoCChfoIFAAAmx9BLWEY383.png

wKiom1cPoCDTmcyXAABdLcL5Gbs624.png

 

 

 

3、單繼承(含有虛函數的覆蓋)

class Base
{
public:
                 virtual void FunTest1()
                {
                                cout << "Base::FunTest1()" << endl;
                }
                 virtual void FunTest2()
                {
                                cout << "Base::FunTest2()" << endl;
                }
                 int _data1;
};
class Derive :public Base
{
public:
                 virtual void FunTest1()//覆蓋基類中的FunTest1
                {
                                cout << "Derive::FunTest1()" << endl;
                }
                 virtual void FunTest3()
                {
                                cout << "Derive::FunTest3()" << endl;
                }
                 virtual void FunTest4()
                {
                                cout << "Derive::FunTest4()" << endl;
                }
                 int _data2;
};
typedef void (*VtbFun)();
void PrintVtable()
{
                cout << "Derive類的虛函數表: " << endl;
                 Derive d1;
                d1._data1 = 0x01;
                d1._data2 = 0x02;

                 int* pVTable = (int *)*(int*)&d1;
                 VtbFun FunTest = (VtbFun )*pVTable;
                 while (NULL != FunTest)
                {
                                FunTest();
                                cout << ( int*)FunTest << endl;
                                pVTable += 1;
                                FunTest = ( VtbFun)*pVTable;
                }
                cout << "虛表結束: " << endl;
}
int main()
{
                PrintVtable();
                 return 0;
}


 

派生類對象模型及虛表建立規則:先將基類的虛表搬移過來,若派生類對基類中的某個函數進行了重寫,則會用派生類重寫的虛函數的地址替換掉虛表中相應位置基類中虛函數的地址,替換完之後再將派生類自己的虛函數地址按照聲明的順序添加到虛表中

wKioL1cPoSLwHX5HAAB-nbW62wY676.png

4、多繼承(沒有虛函數的覆蓋)

class Base
{
public:
                 virtual void FunTest1()
                {
                                cout << "Base::FunTest1()" << endl;
                }
                 virtual void FunTest2()
                {
                                cout << "Base::FunTest2()" << endl;
                }
                 int _data1;

};

class Base1
{
public:
                 virtual void FunTest3()
                {
                                cout << "Base1::FunTest3()" << endl;
                }
                 virtual void FunTest4()
                {
                                cout << "Base1::FunTest4()" << endl;
                }
                 int _data2;
};

class Derive :public Base, public Base1
{
public:
                 virtual void FunTest5()
                {
                                cout << "Derive::FunTest5()" << endl;
                }
                 int _data3;
};

typedef void (*VtbFun)();
void PrintVtable()
{
                cout << "Derive類的虛函數表: " << endl;
                 Derive d1;
                d1._data1 = 0x01;
                d1._data2 = 0x02;
                 int* pVTable = (int *)*(int*)&d1;
                 VtbFun FunTest = (VtbFun )*pVTable;
                 while (NULL != FunTest)
                {
                                FunTest();
                                cout << ( int*)FunTest << endl;
                                pVTable += 1;
                                FunTest = ( VtbFun)*pVTable;
                }
                cout << "虛表結束. " << endl;
}

int main()
{
                 Derive d;
                d._data1 = 0x01;
                d._data2 = 0x02;
                d._data3 = 0x03;
                PrintVtable();
                 return 0;
}

 

5、多繼承(含有虛函數的覆蓋)

classBase
{
public:
virtualvoidFunTest1()
{
cout<<"Base::FunTest1()"<

 

此時派生類的對象模型和虛表的結構:

派生類虛表建立過程:先建立和Base1相同的部分,在Derive中對FunTest3進行了重寫,所以替換掉虛表中原來的Base1::FunTest3改為了Derive::FunTest3,為了提高訪問速度,將自己特有的虛函數加在第一份虛表的後面,建立Base虛表的過程與Base1相同。

wKiom1cPoKWjXjbWAACL6VVhd8g205.png

6、虛擬繼承

classBase
{
public:
virtualvoidFunTest1()
{
cout<<"Base::FunTest1()"<

wKiom1cPoMOReqgBAACECDzKWPk461.png

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved