dynamic_cast实现原理

在使用dynamic_cast时,查看的反汇编,假设C是派生类,A是基类

 A* pa = new C;
  C * c = dynamic_cast<C *>(pa); 

其中调用了___RTDynamicCast,

http://en.verysource.com/winceos-99192.html 中有

其中便有其实现,为了不和编译器中的 ___RTDynamicCast冲突,新建两个文件:rtti.h和rtti.cpp,将___RTDynamicCast修改为___RTDynamicCastMY,并注释掉一些抛异常。内容如下:

rtti.h

#pragma once

extern "C" {
#include <windows.h>
};

typedef const type_info TypeDescriptor;

struct PMD
{
  ptrdiff_t mdisp; //vftable offset
  ptrdiff_t pdisp; //vftable offset
  ptrdiff_t vdisp; //vftable offset(for virtual base class)
};

typedef const struct _s_RTTIBaseClassDescriptor
{
  TypeDescriptor                  *pTypeDescriptor;
  DWORD                           numContainedBases;
  PMD                             where;
  DWORD                           attributes;
} _RTTIBaseClassDescriptor;

typedef const struct  _s_RTTIBaseClassArray
{
  _RTTIBaseClassDescriptor* arrayOfBaseClassDescriptors[3];
}_RTTIBaseClassArray;

typedef const struct _s_RTTIClassHierarchyDescriptor
{
  DWORD                           signature;
  DWORD                           attributes;
  DWORD                           numBaseClasses;
  _RTTIBaseClassArray             *pBaseClassArray;
}_RTTIClassHierarchyDescriptor;

typedef const struct _s_RTTICompleteObjectLocator
{
  DWORD                           signature;
  DWORD                           offset;			 //vftbl相对this的偏移
  DWORD                           cdOffset;		 //constructor displacement 
  TypeDescriptor                  *pTypeDescriptor;
  _RTTIClassHierarchyDescriptor   *pClassDescriptor;
}_RTTICompleteObjectLocator;

#define BCD_NOTVISIBLE              0x00000001
#define BCD_AMBIGUOUS               0x00000002
#define BCD_PRIVORPROTINCOMPOBJ     0x00000004
#define BCD_PRIVORPROTBASE          0x00000008
#define BCD_VBOFCONTOBJ             0x00000010
#define BCD_NONPOLYMORPHIC          0x00000020

#define BCD_PTD(bcd)                ((bcd).pTypeDescriptor)
#define BCD_NUMCONTBASES(bcd)       ((bcd).numContainedBases)
#define BCD_WHERE(bcd)              ((bcd).where)
#define BCD_ATTRIBUTES(bcd)         ((bcd).attributes)

#define CHD_MULTINH                 0x00000001 //多重继承
#define CHD_VIRTINH                 0x00000002 //虚拟继承
#define CHD_AMBIGUOUS               0x00000004 //有重复基类的多重继承

#define CHD_SIGNATURE(chd)          ((chd).signature)
#define CHD_ATTRIBUTES(chd)         ((chd).attributes)
#define CHD_NUMBASES(chd)           ((chd).numBaseClasses)
#define CHD_PBCA(chd)               ((chd).pBaseClassArray)

#define COL_SIGNATURE(col)          ((col).signature)
#define COL_OFFSET(col)             ((col).offset)
#define COL_CDOFFSET(col)           ((col).cdOffset)
#define COL_PTD(col)                ((col).pTypeDescriptor)
#define COL_PCHD(col)               ((col).pClassDescriptor)

extern "C" PVOID __cdecl __RTDynamicCastMY(PVOID, LONG, PVOID, PVOID, BOOL);

extern "C" PVOID __cdecl __RTtypeidMY(PVOID);     // ptr to vfptr

#define TYPEIDS_EQ(pID1, pID2)  ((pID1 == pID2) || !strcmp(pID1->name(), pID2->name()))

rtti.cpp

#include <stdio.h>
#include <typeinfo>
#include "rtti.h"
 
#pragma warning(disable:4297)
 
static PVOID __cdecl FindCompleteObject(PVOID *);
static _RTTIBaseClassDescriptor * __cdecl FindSITargetTypeInstance(PVOID,_RTTICompleteObjectLocator *,TypeDescriptor *,int,TypeDescriptor *);
static _RTTIBaseClassDescriptor * __cdecl FindMITargetTypeInstance(PVOID,_RTTICompleteObjectLocator *,TypeDescriptor *,int,TypeDescriptor *);
static _RTTIBaseClassDescriptor * __cdecl FindVITargetTypeInstance(PVOID,_RTTICompleteObjectLocator *,TypeDescriptor *,int,TypeDescriptor *);
static ptrdiff_t __cdecl PMDtoOffset(PVOID pThis, const PMD& pmd);
 
extern "C" PVOID __cdecl __RTtypeidMY (PVOID inptr)         
{
    if (!inptr) {
        //throw std::bad_typeid ("Attempted a typeid of NULL pointer!"); 
        return NULL;
    }
 
    __try {
        // Ptr to CompleteObjectLocator should be stored at vfptr[-1]
        _RTTICompleteObjectLocator *pCompleteLocator = (_RTTICompleteObjectLocator *) ((*((void***)inptr))[-1]);
        return (PVOID) pCompleteLocator->pTypeDescriptor;
    }
    __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER:		        EXCEPTION_CONTINUE_SEARCH) 
	{
        //throw std::__non_rtti_object ("Access violation - no RTTI data!");
    }
}
 
 
extern "C" PVOID __cdecl __RTDynamicCastMY (
                                        PVOID inptr,         // Pointer to polymorphic object
                                        LONG VfDelta,       // Offset of vfptr in object
                                        PVOID SrcType,      // Static type of object pointed to by inptr
                                        PVOID TargetType,   // Desired result of cast
                                        BOOL isReference)   // TRUE if input is reference, FALSE if input is ptr
{
    PVOID pResult;
    _RTTIBaseClassDescriptor *pBaseClass;
 
    if (inptr == NULL)
        return NULL;
 
    __try {
        PVOID pCompleteObject = FindCompleteObject((PVOID *)inptr);
        _RTTICompleteObjectLocator *pCompleteLocator = (_RTTICompleteObjectLocator *) ((*((void***)inptr))[-1]);
 
        // Adjust by vfptr displacement, if any
        inptr = (PVOID *) ((char *)inptr - VfDelta);
        // Calculate offset of source object in complete object
        int inptr_delta = (char *)inptr - (char *)pCompleteObject;
 
        if (!(CHD_ATTRIBUTES(*COL_PCHD(*pCompleteLocator)) & CHD_MULTINH)) {             // if not multiple inheritance
            pBaseClass = FindSITargetTypeInstance(pCompleteObject,
                                                  pCompleteLocator,
                                                  (TypeDescriptor *) SrcType,
                                                  inptr_delta,
                                                  (TypeDescriptor *) TargetType);
        } else if (!(CHD_ATTRIBUTES(*COL_PCHD(*pCompleteLocator)) & CHD_VIRTINH)) { // if multiple, but not virtual, inheritance
            pBaseClass = FindMITargetTypeInstance(pCompleteObject,
                                                  pCompleteLocator,
                                                  (TypeDescriptor *) SrcType,
                                                  inptr_delta,
                                                  (TypeDescriptor *) TargetType);
        } else {                                                                   // if virtual inheritance
            pBaseClass = FindVITargetTypeInstance(pCompleteObject,
                                                  pCompleteLocator,
                                                  (TypeDescriptor *) SrcType,
                                                  inptr_delta,
                                                  (TypeDescriptor *) TargetType);
        }
 
        if (pBaseClass != NULL) {
            // Calculate ptr to result base class from pBaseClass->where
            pResult = ((char *) pCompleteObject) + PMDtoOffset(pCompleteObject, pBaseClass->where);
        }else {
            pResult = NULL;
            if (isReference) {
              //  throw std::bad_cast("Bad dynamic_cast!");
            }
        }
 
    }
    __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH) {
        pResult = NULL;
       // throw std::__non_rtti_object ("Access violation - no RTTI data!");
    }
 
    return pResult;
        
}
 
//
// FindCompleteObject - Calculate member offset from PMD & this
//
// Output: pointer to the complete object containing class *inptr
//
// Side-effects: NONE.
//
static PVOID __cdecl FindCompleteObject (PVOID *inptr)          // Pointer to polymorphic object
{
    // Ptr to CompleteObjectLocator should be stored at vfptr[-1]
    _RTTICompleteObjectLocator *pCompleteLocator = (_RTTICompleteObjectLocator *) ((*((void***)inptr))[-1]);
    char *pCompleteObject = (char *)inptr - pCompleteLocator->offset;
    // Adjust by construction displacement, if any
    if (pCompleteLocator->cdOffset)
        pCompleteObject += *(ptrdiff_t *)((char *)inptr - pCompleteLocator->cdOffset);
    return (PVOID) pCompleteObject;
}
 
static _RTTIBaseClassDescriptor * __cdecl FindSITargetTypeInstance (
                                PVOID pCompleteObject,                          // pointer to complete object
                                _RTTICompleteObjectLocator *pCOLocator, // pointer to Locator of complete object
                                TypeDescriptor *pSrcTypeID,        // pointer to TypeDescriptor of source object
                                int SrcOffset,                                          // offset of source object in complete object
                                TypeDescriptor *pTargetTypeID)     // pointer to TypeDescriptor of result of cast
{
    _RTTIBaseClassDescriptor *pBase;
    _RTTIBaseClassDescriptor * const *pBasePtr;
    DWORD i;
 
    for (i = 0, pBasePtr = pCOLocator->pClassDescriptor->pBaseClassArray->arrayOfBaseClassDescriptors;
         i < pCOLocator->pClassDescriptor->numBaseClasses;
         i++, pBasePtr++) {
 
        // Test type of selected base class
        pBase = *pBasePtr;
        if (TYPEIDS_EQ(pBase->pTypeDescriptor, pTargetTypeID) &&
            !(BCD_ATTRIBUTES(*pBase) & BCD_NOTVISIBLE)) {
            return pBase;
        }
    }
    return NULL;
}
 
static _RTTIBaseClassDescriptor * __cdecl FindMITargetTypeInstance (
                                PVOID pCompleteObject,                          // pointer to complete object
                                _RTTICompleteObjectLocator *pCOLocator, // pointer to Locator of complete object
                                TypeDescriptor *pSrcTypeID,        // pointer to TypeDescriptor of source object
                                int SrcOffset,                                          // offset of source object in complete object
                                TypeDescriptor *pTargetTypeID)     // pointer to TypeDescriptor of result of cast
{
    _RTTIBaseClassDescriptor *pBase, *pSubBase;
    _RTTIBaseClassDescriptor * const *pBasePtr, * const *pSubBasePtr;
    DWORD i, j;
 
                                // First, try down-casts
    for (i = 0, pBasePtr = pCOLocator->pClassDescriptor->pBaseClassArray->arrayOfBaseClassDescriptors;
         i < pCOLocator->pClassDescriptor->numBaseClasses;
         i++, pBasePtr++) {
        
        pBase = *pBasePtr;
                                // Test type of selected base class
        if (TYPEIDS_EQ(pBase->pTypeDescriptor, pTargetTypeID)) {
                                // If base class is proper type, see if it contains our instance of source class
            for (j = 0, pSubBasePtr = pBasePtr+1;
                 j < pBase->numContainedBases;
                 j++, pSubBasePtr++) {
 
                pSubBase = *pSubBasePtr;
                if (TYPEIDS_EQ(pSubBase->pTypeDescriptor, pSrcTypeID) &&
                    (PMDtoOffset(pCompleteObject, pSubBase->where) == SrcOffset)) {
                                // Yes, this is the proper instance of source class
                    return pBase;
                }
            }
        }
    }
 
                                // Down-cast failed, try cross-cast
    for (i = 0, pBasePtr = pCOLocator->pClassDescriptor->pBaseClassArray->arrayOfBaseClassDescriptors;
         i < pCOLocator->pClassDescriptor->numBaseClasses;
         i++, pBasePtr++) {
 
        pBase = *pBasePtr;
                                // Check if base class has proper type, is accessible & is unambiguous
        if (TYPEIDS_EQ(pBase->pTypeDescriptor, pTargetTypeID) &&
            !(BCD_ATTRIBUTES(*pBase) & BCD_NOTVISIBLE) &&
            !(BCD_ATTRIBUTES(*pBase) & BCD_AMBIGUOUS)) {
            return pBase;
        }
    }
 
    return NULL;
}
 
static _RTTIBaseClassDescriptor * __cdecl FindVITargetTypeInstance (
                                PVOID pCompleteObject,                          // pointer to complete object
                                _RTTICompleteObjectLocator *pCOLocator, // pointer to Locator of complete object
                                TypeDescriptor *pSrcTypeID,        // pointer to TypeDescriptor of source object
                                int SrcOffset,                                          // offset of source object in complete object
                                TypeDescriptor *pTargetTypeID)     // pointer to TypeDescriptor of result of cast
{
    _RTTIBaseClassDescriptor *pBase, *pSubBase;
    _RTTIBaseClassDescriptor * const *pBasePtr, * const *pSubBasePtr;
    _RTTIBaseClassDescriptor *pResult = NULL;
    DWORD i, j;
 
                                // First, try down-casts
    for (i = 0, pBasePtr = pCOLocator->pClassDescriptor->pBaseClassArray->arrayOfBaseClassDescriptors;
         i < pCOLocator->pClassDescriptor->numBaseClasses;
         i++, pBasePtr++) {
        
        pBase = *pBasePtr;
                                // Test type of selected base class
        if (TYPEIDS_EQ(pBase->pTypeDescriptor, pTargetTypeID)) {
                                // If base class is proper type, see if it contains our instance of source class
            for (j = 0, pSubBasePtr = pBasePtr+1;
                 j < pBase->numContainedBases;
                 j++, pSubBasePtr++) {
 
                pSubBase = *pSubBasePtr;
                if (TYPEIDS_EQ(pSubBase->pTypeDescriptor, pSrcTypeID) &&
                    (PMDtoOffset(pCompleteObject, pSubBase->where) == SrcOffset)) {
                                // Yes, this is the proper instance of source class - make sure it is unambiguous
                                // Ambiguity now determined by inequality of offsets of source class within complete object, not pointer inequality
                    if ((pResult != NULL) && (PMDtoOffset(pCompleteObject, pResult->where) != PMDtoOffset(pCompleteObject, pBase->where))) {
                                // We already found an earlier instance, hence ambiguity
                        return NULL;
                    }
                    else {
                                // Unambiguous
                        pResult = pBase;
                    }
                }
            }
        }
    }
 
    if (pResult != NULL)
        return pResult;
 
                                // Down-cast failed, try cross-cast
    for (i = 0, pBasePtr = pCOLocator->pClassDescriptor->pBaseClassArray->arrayOfBaseClassDescriptors;
         i < pCOLocator->pClassDescriptor->numBaseClasses;
         i++, pBasePtr++) {
 
        pBase = *pBasePtr;
                                // Check if base class has proper type, is accessible & is unambiguous
        if (TYPEIDS_EQ(pBase->pTypeDescriptor, pTargetTypeID) &&
            !(BCD_ATTRIBUTES(*pBase) & BCD_NOTVISIBLE) &&
            !(BCD_ATTRIBUTES(*pBase) & BCD_AMBIGUOUS)) {
            return pBase;
 
        }
    }
 
    return NULL;
}
 
static ptrdiff_t __cdecl PMDtoOffset(
                                PVOID pThis,                    // ptr to complete object
                                const PMD& pmd)                 // pointer-to-member-data structure
{
    ptrdiff_t RetOff = 0;
 
    if (pmd.pdisp >= 0) {                       // if base is in the virtual part of class
        RetOff = pmd.pdisp;
        RetOff += *(ptrdiff_t*)((char*)*(ptrdiff_t*)((char*)pThis + RetOff) + pmd.vdisp);
    }
 
    RetOff += pmd.mdisp;
 
    return RetOff;
}

 

1 单继承

// WinDemo.cpp : 定义控制台应用程序的入口点。
//
#include <iostream>
#include "rtti.h"
using namespace std;

class A
{
public:
  virtual void func()
  {
    cout << "A::func()" << endl;
  }
};

class B 
{
public:
  virtual void func()
  {
    cout << "B::func()" << endl;
  }
};

class C : public A
{
public:
  virtual void func()
  {
    cout << "C::func()" << endl;
  }
private:
  int _val;
};


int main(int argc, char* argv[])
{
  A* pa = new C;  
  TypeDescriptor* ptypeA = &typeid(A);
  TypeDescriptor* ptypeC = &typeid(C);
  C* pc = (C*)__RTDynamicCastMY(pa, 0, (LPVOID)ptypeA, (LPVOID)ptypeC, FALSE);
  cout << pc << endl;
  return 0;
}

类C继承类A,内存布局:

 下断点:

extern "C" PVOID __cdecl __RTDynamicCastMY (
                                        PVOID inptr,         // Pointer to polymorphic object
                                        LONG VfDelta,       // Offset of vfptr in object
                                        PVOID SrcType,      // Static type of object pointed to by inptr
                                        PVOID TargetType,   // Desired result of cast
                                        BOOL isReference)   // TRUE if input is reference, FALSE if input is ptr
{
    PVOID pResult;
    _RTTIBaseClassDescriptor *pBaseClass;
 
    if (inptr == NULL)
        return NULL;
 
    __try {
        PVOID pCompleteObject = FindCompleteObject((PVOID *)inptr);//从基类指针的内存地址根据offset找到类的起始位置;
        _RTTICompleteObjectLocator *pCompleteLocator = (_RTTICompleteObjectLocator *) ((*((void***)inptr))[-1]);//找到类C的虚函数表中rtti信息,存储在[-1]中
 
        // Adjust by vfptr displacement, if any
        inptr = (PVOID *) ((char *)inptr - VfDelta);
        // Calculate offset of source object in complete object
        int inptr_delta = (char *)inptr - (char *)pCompleteObject;//计算基类和类C的地址偏移
 
        if (!(CHD_ATTRIBUTES(*COL_PCHD(*pCompleteLocator)) & CHD_MULTINH)) {             // if not multiple inheritance  单继承情况
            pBaseClass = FindSITargetTypeInstance(pCompleteObject,
                                                  pCompleteLocator,
                                                  (TypeDescriptor *) SrcType,
                                                  inptr_delta,
                                                  (TypeDescriptor *) TargetType);
        } 
......
    __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH) {
        pResult = NULL;
       // throw std::__non_rtti_object ("Access violation - no RTTI data!");
    }
 
    return pResult;
        
}

 其中:

(_RTTICompleteObjectLocator *)((*((void***)inptr))[-1])是取出虚表中的前一项,,虚表的前一项是RTTI的信息,这个结构的具体信息:

_RTTICompleteObjectLocator

这个是整个RTTI的结构定义,具体结构如下:

typedef const struct	_s_RTTICompleteObjectLocator	{
	DWORD							signature;
	DWORD							offset;
	DWORD							cdOffset;
	TypeDescriptor					*pTypeDescriptor;
	_RTTIClassHierarchyDescriptor	*pClassDescriptor;
	} _RTTICompleteObjectLocator;

其中:

  1. signature : RTTI的签名。
  2. offset : 相对于对象开始的偏移量.
  3. cdOffset : 暂时不知道什么意思。
  4. pTypeDescriptor : 类的type_info结构。
  5. pClassDescriptor : 基类的描述信息。

TypeDescriptor

TypeDescriptor 即 type_info ,type_info 中有一个成员变量:

 mutable __std_type_info_data _Data;

其中_DecoratedName记录了当前类的名称

typedef const type_info TypeDescriptor;
class type_info
{
public:

    type_info(const type_info&) = delete;
    type_info& operator=(const type_info&) = delete;

    size_t hash_code() const noexcept
    {
        return __std_type_info_hash(&_Data);
    }

    bool operator==(const type_info& _Other) const noexcept
    {
        return __std_type_info_compare(&_Data, &_Other._Data) == 0;
    }

    bool operator!=(const type_info& _Other) const noexcept
    {
        return __std_type_info_compare(&_Data, &_Other._Data) != 0;
    }

    bool before(const type_info& _Other) const noexcept
    {
        return __std_type_info_compare(&_Data, &_Other._Data) < 0;
    }

    const char* name() const noexcept
    {
        #ifdef _M_CEE_PURE
        return __std_type_info_name(&_Data, static_cast<__type_info_node*>(__type_info_root_node.ToPointer()));
        #else
        return __std_type_info_name(&_Data, &__type_info_root_node);
        #endif
    }

    const char* raw_name() const noexcept
    {
        return _Data._DecoratedName;
    }

    virtual ~type_info() noexcept;

private:

    mutable __std_type_info_data _Data;
};


struct __std_type_info_data
{
    const char * _UndecoratedName;
    const char   _DecoratedName[1];
    __std_type_info_data() = delete;
    __std_type_info_data(const __std_type_info_data&) = delete;
    __std_type_info_data(__std_type_info_data&&) = delete;

    __std_type_info_data& operator=(const __std_type_info_data&) = delete;
    __std_type_info_data& operator=(__std_type_info_data&&) = delete;
};

_RTTIClassHierarchyDescriptor

typedef const struct	_s_RTTIClassHierarchyDescriptor {
	DWORD							signature;
	DWORD							attributes;
	DWORD							numBaseClasses;
	_RTTIBaseClassArray				*pBaseClassArray;
} _RTTIClassHierarchyDescriptor;

#define CHD_MULTINH					0x00000001
#define CHD_VIRTINH					0x00000002
#define CHD_AMBIGUOUS				0x00000004

其中 attributes的定义为CHD_xxxx分别如下:
CHD_MULTINH=0x00000001 : 表示多继承。
CHD_VIRTINH=0x00000002 : 存在虚拟继承。
CHD_AMBIGUOUS=0x00000004 : 继承情况模糊不清。
numBaseClasses : 表示基类的个数。
pBaseClassArray : 基类的描述数组。

_RTTIBaseClassArray

这个结构是基类数组描述,结构定义如下:其中存储了一个的基类,其中包括自己

typedef const struct	_s_RTTIBaseClassArray {
	_RTTIBaseClassDescriptor		*arrayOfBaseClassDescriptors[];
} _RTTIBaseClassArray;

typedef const struct	_s_RTTIBaseClassDescriptor {
	TypeDescriptor					*pTypeDescriptor;
	DWORD							numContainedBases;
	PMD								where;
	DWORD							attributes;
} _RTTIBaseClassDescriptor;

typedef struct PMD
{
	ptrdiff_t	mdisp;		// Offset of intended data within base
	ptrdiff_t	pdisp;		// Displacement to virtual base pointer
	ptrdiff_t	vdisp;		// Index within vbTable to offset of base
} PMD;

#define BCD_NOTVISIBLE				0x00000001
#define BCD_AMBIGUOUS				0x00000002
#define BCD_PRIVORPROTINCOMPOBJ		0x00000004
#define BCD_PRIVORPROTBASE			0x00000008
#define BCD_VBOFCONTOBJ				0x00000010
#define BCD_NONPOLYMORPHIC			0x00000020

 

如:

(1) C单继承A,因此offset为0;

(2)_DecoratedName中可以看出类C存储的名称为:0x001bd154 ".?AVC@@"

(3)从pBaseClassArray中,可以看出类C有两个基类,分别是C,A 为什么要记录C呢,这个东西在dynastic_cast中有用

计算单继承中 down_cast:

static _RTTIBaseClassDescriptor * __cdecl FindSITargetTypeInstance (
                                PVOID pCompleteObject,                          // pointer to complete object
                                _RTTICompleteObjectLocator *pCOLocator, // pointer to Locator of complete object
                                TypeDescriptor *pSrcTypeID,        // pointer to TypeDescriptor of source object
                                int SrcOffset,                                          // offset of source object in complete object
                                TypeDescriptor *pTargetTypeID)     // pointer to TypeDescriptor of result of cast
{
    _RTTIBaseClassDescriptor *pBase;
    _RTTIBaseClassDescriptor * const *pBasePtr;
    DWORD i;
    //从基类的数组中查找是否存在匹配的基类,如果存在则返回
    for (i = 0, pBasePtr = pCOLocator->pClassDescriptor->pBaseClassArray->arrayOfBaseClassDescriptors;
         i < pCOLocator->pClassDescriptor->numBaseClasses;
         i++, pBasePtr++) {
 
        // Test type of selected base class
        pBase = *pBasePtr;
        if (TYPEIDS_EQ(pBase->pTypeDescriptor, pTargetTypeID) &&
            !(BCD_ATTRIBUTES(*pBase) & BCD_NOTVISIBLE)) {
            return pBase;
        }
    }
    return NULL;
}

2 多继承

// WinDemo.cpp : 定义控制台应用程序的入口点。
//
#include <iostream>
#include "rtti.h"
using namespace std;

class A
{
public:
  virtual void func()
  {
    cout << "A::func()" << endl;
  }
};

class B 
{
public:
  virtual void func()
  {
    cout << "B::func()" << endl;
  }
};

class C : public B,public A
{
public:
  virtual void func()
  {
    cout << "C::func()" << endl;
  }
private:
  int _val;
};


int main(int argc, char* argv[])
{
  A* pa = new C;  
  TypeDescriptor* ptypeA = &typeid(A);
  TypeDescriptor* ptypeC = &typeid(C);
  C* pc = (C*)__RTDynamicCastMY(pa, 0, (LPVOID)ptypeA, (LPVOID)ptypeC, FALSE);
  cout << pc << endl;
  return 0;
}

其中,特意让C先继承B,这样当  A* pa = new C; 时 A类的虚函数指针在类C中的内存中有偏移,如下:

 

在FindCompleteObject 中,

 会根据基类A类型的指针,通过虚表中_RTTICompleteObjectLocator记录的offset找到类C的开始地址

 

static PVOID __cdecl FindCompleteObject (PVOID *inptr)          // Pointer to polymorphic object
{
    // Ptr to CompleteObjectLocator should be stored at vfptr[-1]
    _RTTICompleteObjectLocator *pCompleteLocator = (_RTTICompleteObjectLocator *) ((*((void***)inptr))[-1]);
    char *pCompleteObject = (char *)inptr - pCompleteLocator->offset;
    // Adjust by construction displacement, if any
    if (pCompleteLocator->cdOffset)
        pCompleteObject += *(ptrdiff_t *)((char *)inptr - pCompleteLocator->cdOffset);
    return (PVOID) pCompleteObject;
}

即   char *pCompleteObject = (char *)inptr - pCompleteLocator->offset;找到类C的内存开始地址

多继承下dynastic_cast转换:

 

static _RTTIBaseClassDescriptor * __cdecl FindMITargetTypeInstance (
                                PVOID pCompleteObject,                          // pointer to complete object
                                _RTTICompleteObjectLocator *pCOLocator, // pointer to Locator of complete object
                                TypeDescriptor *pSrcTypeID,        // pointer to TypeDescriptor of source object
                                int SrcOffset,                                          // offset of source object in complete object
                                TypeDescriptor *pTargetTypeID)     // pointer to TypeDescriptor of result of cast
{
    _RTTIBaseClassDescriptor *pBase, *pSubBase;
    _RTTIBaseClassDescriptor * const *pBasePtr, * const *pSubBasePtr;
    DWORD i, j;
 
                                // First, try down-casts 首先找到目标类C
    for (i = 0, pBasePtr = pCOLocator->pClassDescriptor->pBaseClassArray->arrayOfBaseClassDescriptors;
         i < pCOLocator->pClassDescriptor->numBaseClasses;
         i++, pBasePtr++) {
        
        pBase = *pBasePtr;
                                // Test type of selected base class
        if (TYPEIDS_EQ(pBase->pTypeDescriptor, pTargetTypeID)) {
                                // If base class is proper type, see if it contains our instance of source class
            //如果找到目标类C,继续找看是否能找到目标类A,以证明存在合法的继承关系
            for (j = 0, pSubBasePtr = pBasePtr+1;
                 j < pBase->numContainedBases;
                 j++, pSubBasePtr++) {
 
                pSubBase = *pSubBasePtr;
                if (TYPEIDS_EQ(pSubBase->pTypeDescriptor, pSrcTypeID) &&
                    (PMDtoOffset(pCompleteObject, pSubBase->where) == SrcOffset)) {
                                // Yes, this is the proper instance of source class
                    return pBase;//找到,返回类C的内存起始地址
                }
            }
        }
    }
 
                                // Down-cast failed, try cross-cast
    for (i = 0, pBasePtr = pCOLocator->pClassDescriptor->pBaseClassArray->arrayOfBaseClassDescriptors;
         i < pCOLocator->pClassDescriptor->numBaseClasses;
         i++, pBasePtr++) {
 
        pBase = *pBasePtr;
                                // Check if base class has proper type, is accessible & is unambiguous
        if (TYPEIDS_EQ(pBase->pTypeDescriptor, pTargetTypeID) &&
            !(BCD_ATTRIBUTES(*pBase) & BCD_NOTVISIBLE) &&
            !(BCD_ATTRIBUTES(*pBase) & BCD_AMBIGUOUS)) {
            return pBase;
        }
    }
 
    return NULL;
}

 用A* 指向派生类,offset为4;

_Data中 时:?AVC@@ 即类C;

attributes:1 表示多继承

pClassDescriptor:中看到有三个基类C B A 其中A的mdisp=4,即在A类虚函数指针在内存布局中的偏移

参考:

C++ dynamic_cast实现原理_passion_wu128的专栏-CSDN博客_dynamic_cast原理

C++ RTTI 实现原理详解_xdesk的专栏-CSDN博客_c++ rtti



dynamic_cast, RTTI, 整理 - Dirichlet - 博客园

工程资源:https://download.csdn.net/download/LIJIWEI0611/31230142

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值