多繼承的虛指針

網上見到一篇:

們首先看一下它的簡化版本dynamic_cast <void *>

根據標準5.2.7-7,dynamic_cast <void *> 會將當前指針轉化爲指向實際對象(most derived object)的指針。
比如說:

class T1 {public : virtual ~T1 () {}};
class T2 {public : virtual ~T2 () {}};
class T3 :public T1 ,public T2 {};
 
int main ()
{
     T3 t ;
     T2 *pt =&t ;
     cout <<((size_t )pt ==(size_t )&t )<<endl ; //output 0
     void *pv =dynamic_cast <void *>(pt );
     cout <<((size_t )pv ==(size_t )&t )<<endl ; //output 1
}

可以看到,經過轉換之後,pv已經指向了原來的t對象。
現在我們來看一下dynamic_cast <void *>內部是怎麼實現的:

void *FindCompleteObject (void *ptr )
{
     const _s_RTTICompleteObjectLocator *pCompleteLocator =GetCompleteObjectLocator (ptr );
     ptr =ptr -pCompleteLocator ->offset ;
     if (pCompleteLocator ->cdOffset ) ptr -=*(ptr -pCompleteLocator ->cdOffset );
     return ptr ;
}
void *__RTCastToVoid (void *ptr )
{
     if (!ptr ) return NULL ;
     return FindCompleteObject (ptr );
}

可以看到,和typeid的實現類似,首先編譯器調整傳入的指針得到vftable,然後據此定位
_RTTICompleteObjectLocator 結構。裏面包含了足夠的信息從當前指針找到實際對象所在的位置。
對於一般的
dynamic_cast 實現,它內部也會首先定位到實際對象所在的位置,然後再進行搜索。

 

 

試了一下:

class A
{
public:
    virtual void func(){}
};

class B
{
public:
    virtual void func(){}
};

class C: public A, public B
{
public:
    int a;
    virtual void t(){}
};
int main()
{
    C c;
    B* pB = &c;
    A* pA = &c;
    printf("Class A pointer: %d/n", pA);
    printf("Class B pointer: %d/n", pB);
    printf("Class C pointer: %d/n", &c);
    printf("Class C member: %d/n", &c.a);
    return 0;
}

 

結果爲:

Class A pointer: 1245028
Class B pointer: 1245032
Class C pointer: 1245028
Class C member: 1245036

 

可見多繼承時,每個路徑會有一個虛指針


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章