dynamic_cast是一个操作符,其用法不再赘述。查看汇编码可以发现实际调用的是这个函数__RTDynamicCast,其内部实现如下:
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 __RTDynamicCast (PVOID, LONG, PVOID, PVOID, BOOL);
- extern "C" PVOID __cdecl __RTtypeid (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 __RTtypeid (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 __RTDynamicCast (
- 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;
- }
测试代码:
- // WinDemo.cpp : 定义控制台应用程序的入口点。
- //
- #include "stdafx.h"
- #include <iostream>
- #include "rtti.h"
- using namespace std;
- class A
- {
- public:
- virtual void func()
- {
- cout << "A::func()" << endl;
- }
- };
- class B : public A
- {
- 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*)__RTDynamicCast(pa, 0, (LPVOID)ptypeA, (LPVOID)ptypeC, FALSE);
- cout << pc << endl;
- return 0;
- }
从以上代码可以看出:只能在有虚函数的类层次之间使用dynamic_cast。要实现dynamic_cast,编译器会在每个含有虚函数的类的虚函数表的前四个字节存放一个指向_RTTICompleteObjectLocator结构的指针,当然还要额外空间存放_RTTICompleteObjectLocator及其相关结构的数据。以上面代码的类C来说:
这个_RTTICompleteObjectLocator就是实现dynamic_cast的关键结构。里面存放了vfptr相对this指针的偏移,构造函数偏移(针对虚拟继承),type_info指针,以及类层次结构中其它类的相关信息。如果是多重继承,这些信息更加复杂。
所以,dynamic_cast的时间和空间代价是相对较高的,在设计时应避免使用。
如果整个工程都不需要dynamic_cast,可以禁用运行时类型信息(vs2008默认是启用的),这样编译器就不会产生_RTTICompleteObjectLocator及相关数据。
禁用方法如下:
依次选择【工程属性】、【配置属性】、【C/C++】、【语言】。将【启用运行时类型信息】改为”否“。
http://blog.csdn.net/passion_wu128/article/details/38511957
C++ dynamic_cast实现原理的更多相关文章
-
跟vczh看实例学编译原理——一:Tinymoe的设计哲学
自从<序>胡扯了快一个月之后,终于迎来了正片.之所以系列文章叫<看实例学编译原理>,是因为整个系列会通过带大家一步一步实现Tinymoe的过程,来介绍编译原理的一些知识点. 但 ...
-
【Cocos2d-x 3.x】 场景切换生命周期、背景音乐播放和场景切换原理与源码分析
大部分游戏里有很多个场景,场景之间需要切换,有时候切换的时候会进行背景音乐的播放和停止,因此对这块内容进行了总结. 场景切换生命周期 场景切换用到的函数: bool Setting::init() { ...
-
C++ 多态的实现原理与内存模型
多态在C++中是一个重要的概念,通过虚函数机制实现了在程序运行时根据调用对象来判断具体调用哪一个函数. 具体来说就是:父类类别的指针(或者引用)指向其子类的实例,然后通过父类的指针(或者引用)调用实际 ...
-
cocos2d-x触摸分发器原理
屏幕捕捉到触摸消息的派发流程: 如果有一个组件如果想要接收触摸事件,会通过继承一个CCTouchDelegate接口注册给CCTouchDispatcher,CCTouchDispatcher 中维护 ...
-
c++中多态性、dynamic_cast、父类指针、父类对象、子类指针、子类对象
c++多态性是依靠虚函数和父类指针指向子类对象来实现的.简单来说,父类中定义虚函数,父类指针指向子类对象,父类指针调用函数时调用的就是子类的函数. 父类没有定义虚函数,父类指针指向子类对象时,父类指针 ...
-
Qt核心机制与原理
转: https://blog.csdn.net/light_in_dark/article/details/64125085 ★了解Qt和C++的关系 ★掌握Qt的信号/槽机制的原理和使用方法 ★ ...
-
C++中static_cast和dynamic_cast强制类型转换
在C++标准中,提供了关于类型层次转换中的两个关键字static_cast和dynamic_cast. 一.static_cast关键字(编译时类型检查) 用法:static_cast < ty ...
-
C++中reinterpret_cast、const_cast、static_cast、dynamic_cast的作用与区别
1.reinterpret_cast 作用及原理:将一个类型的指针,转换为另一个类型的指针,这种转换不用修改指针变量值数据存放格式(不改变指针变量值),只需在编译时重新解释指针的类型就可以,当然他也可 ...
-
C/C++杂记:运行时类型识别(RTTI)与动态类型转换原理
运行时类型识别(RTTI)的引入有三个作用: 配合typeid操作符的实现: 实现异常处理中catch的匹配过程: 实现动态类型转换dynamic_cast. 1. typeid操作符的实现 1.1. ...
随机推荐
-
node.js图片上传
1.node-formidable 对文件上传提供帮助的组件 2.app.js var formidable = require('formidable'); var http = require( ...
-
Hadoop.2.x_集群初建
一.部分概念 1. 分布式:一个项目分为多个模块共同完成一个或多个任务,可部署在一个或多个机器 2. 集群:多个机器运行同一个项目或服务 3. 集群上可能运行着零个或多个分布式系统(比如Hadoop, ...
-
paip.Java Annotation注解的作用and 使用
paip.Java Annotation注解的作用and 使用 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog. ...
-
Webx常用接口
最近在学Webx框架, 在了解webx的工作流程后, 必须要会使用自带的接口和类 常用的 Navigator 这个接口中只有两种类型的方法, 及重定向与转发, 一般用在screen包下的类(注意:s ...
-
更改xcode上iphone模拟器颜色的方法--备用
到模拟器的目录下修改图片即可——在Finder中显示,显示模拟器包内容,修改Contents/Resources/frame.png图片!
-
转:用​C​语​言​的​r​a​n​d​(​)​和​s​r​a​n​d​(​)​产​生​伪​随​机​数​的​方​法​总​结
标准库<cstdlib>(被包含于<iostream>中)提供两个帮助生成伪随机数的函数: 函数一:int rand(void): 从srand (seed)中指定的seed开 ...
-
[转]Xcode的快捷键及代码格式化
Xcode比较常用的快捷键,特别是红色标注的,很常用.1. 文件CMD + N: 新文件CMD + SHIFT + N: 新项目CMD + O: 打开CMD + S: 保存CMD+OPt+S:保存所有 ...
-
animation,transform属性
animation属性 使用@keyfarmes属性开启动画步骤 结构体:@keyfarmes name{ from{ } to{ } } @keyfarmes name{ 0%{ } 50%{ } ...
-
Linux的启动流程 (二)
引:本文以RedHat9.0和i386平台为例,剖析了从用户打开电源直到屏幕出现命令行提示符的整个Linux启动过程.并且介绍了启动中涉及到的各种文件.阅读Linux源代码,无疑是深入学习Linux的 ...
-
JAVA执行远端服务器的脚本
JAVA执行远端服务器的脚本 问题描述 实现思路 技术要点 代码实现 问题描述 工作中遇到这样一个问题,我们的应用为了实现高可用会采取双机部署,拓扑图大致如下: 这种方案可以简单的保证高可用,即便应用 ...