程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 單繼承下的虛表布局,繼承表布局

單繼承下的虛表布局,繼承表布局

編輯:C++入門知識

單繼承下的虛表布局,繼承表布局


在C++中,多態表示 “以一個公有基類的指針或引用,尋址出一個派生類對象” 。

假如有調用 ptr->get_c() ,其中ptr是基類指針,get_c()是一個虛函數。要在執行期能正確調用get_c()的實例,我們需要知道:

     1.ptr所指對象的真正類型,以便我們選擇正確的get_c()實例。

     2.get_c()實例的位置,以便我們能夠調用他。

在實現上,編譯時期會構建出來一張虛表,表格中有程序的虛函數的執行期地址。

              為了找到這個表格,每一個類對象被安插一個由編譯器產生的指針,指向虛表。

              為了找到函數地址,每一個虛函數被指派一個表格索引值。

 

如果有代碼例子:

class A
{
protected:
    int a;
public:
    A(const int a) :a(a){}
    virtual ~A();
    virtual int pure_v() = 0; //純虛函數
    virtual int get_b(){ return 0; }
    virtual int get_c(){ return 0; }
};
class B :public A
{
protected:
    int b;
public:
    B(int a = 0, int b = 0):A(a),b(b){}
    ~B();
    int pure_v();
    int get_b(){ return b; }
};
class C :public B
{
protected:
    int c;
public:
    C(int a = 0, int b = 0, int c = 0) :B(a, b), c(c){}
    ~C();
    int pure_v();
    int get_c(){ return c; }
};

一個類只會有一張虛表。每個表內含其對應類對象中三類虛函數,這三類包括:

    1.這一類所定義的虛函數實例或改寫自基類的虛函數實例。如例子中Calss B中的get_b()。

    2.繼承自基類的已被改寫過的函數實例。如例子中Calss C的虛表中會有get_b(),在C中不改寫,而在B中已被改寫過。

    3.一個純虛函數的實例。如Class B中的pure_v()。

接下來我們看類A,B,C的虛表布局。

對於A a; 布局如下:(博主是用visio畫的,有點丑- -)

_vptr是編譯時期產生的虛表指針。

slot 0通常是指出每個類所關聯的type_info object(用以支持RTTI)。

A的虛析構被指派為solt 1。純虛函數被指派為solt 2,但A中的純虛函數沒有定義,如果意外調用了此函數,通常的操作是結束這個程序。

get_b()被指派slot ,get_c()被指派slot 4。

對於B:A b; 布局如下:

B的虛表中在solt 1指出析構函數。A中的純虛函數有了定義,所以在slot 2指出pure_()。

自己的get_b()函數實例地址放在solt 3。繼承自A的get_c()函數實例地址放在solt 4。

對於C:B c; 布局如下:

solt 1放置析構函數地址,solt 2放置pure_v()函數地址,solt 3放置繼承自B的get_b()的函數地址,solt 4放置自己的get_c()函數地址。

 

現在再來看調用ptr->get_c();

*在每次調用get_c()時,我們並不知道ptr所指對象的真正類型。但是我知道通過ptr可以存取到該對象的虛表。

*雖然我不知道哪一個get_c()函數實例會被調用,但是我知道每一個get_c()的函數實例地址都被放在solt 4中。

通過這些信息,編譯器可以把調用改寫為:

                                                   (ptr->_vptr[4])(ptr);  

從而在執行期調用正確的函數實例。

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