dynamic_cast向下转型:运行时如何检查Base是否指向Derived?
dynamic_cast downcasting: How does the runtime check whether Base points to Derived?
我有兴趣了解,一般来说,在使用 dynamic_cast 应用向下转换时,运行时如何检查基 class 是否实际指向派生的 class。
我知道多态 class 的每个虚拟 table 也包含 RTTI(以 type_info 指针的形式)。
每个编译器在实现上都会有细微差别,但我将使用 MSVC 作为参考,因为它们很容易提供 VS 的源代码。
您可以转到 Visual Studio 安装并转到 /Community/VS/Tools/MSVC/${VERSION}/crt/src/vcruntime/rtti.cpp
查看有关 MSVC 如何执行此操作的所有详细信息
编译器将在内部转换 dynamic_cast
以调用函数 __RTDynamicCast
(或 __RTCastToVoid
,如果尝试转换为 void*
),这将接受目标类型和源类型的 RTTI 信息。 _RTTITypeDescriptor
结构中的关键元素是完全修饰的名称。然后它将根据输入类型是单继承、多继承还是虚拟继承分派到 3 种不同实现之一。
对于单继承 FindSITargetTypeInstance
将遍历基本 class 类型的列表,如果通过指针比较找到匹配项,它将 return class描述符。如果通过指针比较未能找到匹配项,它将使用字符串比较重试。
对于多重继承 FindMITargetTypeInstance
将以 depth-first、left-to-right 的顺序遍历 class 层次结构,直到它看到源类型和目标的描述符类型。每个比较都是通过 TypeidsEqual
完成的,它将首先尝试进行指针比较,但会立即回退到字符串比较,这与单继承的不同之处在于单继承是在 2 个单独的循环中完成的,因为指针很可能会匹配。
对于虚拟继承 FindVITargetTypeInstance
将遍历整个 class 层次结构。这是三个中最慢的,因为由于潜在的钻石问题,它不能提前退出。每次比较都是通过 TypeidsEqual
.
完成的
一旦找到该类型的描述符,它将使用它来计算从源指针到目标指针的偏移量。
总的来说,代码相当简单,而且记录得非常好,尽管我确实遗漏了一些细微差别,比如检查基数 class 是否是公开派生的,或者区分 down-casts、up-casts, 和 cross-casts.
我有兴趣了解,一般来说,在使用 dynamic_cast 应用向下转换时,运行时如何检查基 class 是否实际指向派生的 class。 我知道多态 class 的每个虚拟 table 也包含 RTTI(以 type_info 指针的形式)。
每个编译器在实现上都会有细微差别,但我将使用 MSVC 作为参考,因为它们很容易提供 VS 的源代码。
您可以转到 Visual Studio 安装并转到 /Community/VS/Tools/MSVC/${VERSION}/crt/src/vcruntime/rtti.cpp
编译器将在内部转换 dynamic_cast
以调用函数 __RTDynamicCast
(或 __RTCastToVoid
,如果尝试转换为 void*
),这将接受目标类型和源类型的 RTTI 信息。 _RTTITypeDescriptor
结构中的关键元素是完全修饰的名称。然后它将根据输入类型是单继承、多继承还是虚拟继承分派到 3 种不同实现之一。
对于单继承 FindSITargetTypeInstance
将遍历基本 class 类型的列表,如果通过指针比较找到匹配项,它将 return class描述符。如果通过指针比较未能找到匹配项,它将使用字符串比较重试。
对于多重继承 FindMITargetTypeInstance
将以 depth-first、left-to-right 的顺序遍历 class 层次结构,直到它看到源类型和目标的描述符类型。每个比较都是通过 TypeidsEqual
完成的,它将首先尝试进行指针比较,但会立即回退到字符串比较,这与单继承的不同之处在于单继承是在 2 个单独的循环中完成的,因为指针很可能会匹配。
对于虚拟继承 FindVITargetTypeInstance
将遍历整个 class 层次结构。这是三个中最慢的,因为由于潜在的钻石问题,它不能提前退出。每次比较都是通过 TypeidsEqual
.
一旦找到该类型的描述符,它将使用它来计算从源指针到目标指针的偏移量。
总的来说,代码相当简单,而且记录得非常好,尽管我确实遗漏了一些细微差别,比如检查基数 class 是否是公开派生的,或者区分 down-casts、up-casts, 和 cross-casts.