網上見到一篇:
們首先看一下它的簡化版本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
可見多繼承時,每個路徑會有一個虛指針