虚拟方法在没有RTTI的情况下工作,不应该意味着在运行时有足够的数据来确定它是哪个类吗?
(我想知道我如何向下转换,然后检查它是否是指向正确类型的指针。但我无法修改所涉及的类或打开RTTI。)
答案 0 :(得分:2)
虚拟函数调度不需要类型信息,动态类型的标识。
虚函数调度通常通过每个对象中的vtable指针实现,其中该指针指向特定于类型的函数实现指针表(" vtable")。
dynamic_cast
和typeid
需要输入类型信息。
如果typeid
返回类型信息,则该信息必须存在于可执行文件的某个位置。当您关闭信息的存储时,它不会被检索。但是dynamic_cast
呢?
在最简单的情况下,dynamic_cast
是从某个基本类型引用向下转换为派生类型引用,D&
。派生类型不必是对象的派生类型最多。因此,对于现在用于动态调度的通用vtable方案,对象的vtable指针不需要指向D
类型的vtable,因此不能提供简单的成功检查
仍然对于仅限于单一继承的语言,可以通过使用vtable本身作为类型标识符来解决纯粹的低位情况,方法是通过vtable中的父指针搜索(单个)继承链。
在图片中有多重继承,事情变得复杂。例如,如果类Derived
继承自Base1
和Base2
,两者都是多态的,那么Derived
类' vtable不能简单地扩展Base1
的vtable 和只是扩展Base2
的vtable。因此,如果Derived
vtable延伸Base1
,那么当人们将Derived*
重新解释为Base2*
时,指向的对象{{1} vtable指针将不再用作指向静态已知类的指针。虚表。
因此,一个结果是,在存在多重继承的情况下,转换为基类型引用并不总是对指针类型的简单重新解释 - 可能必须调整指针值。
如何做到这一点是非常明显的,Bjarne Stroustrup必须向自己证明,在向该语言添加多重继承之前,可以实现多重继承的vtable方案。
我不知道当前的编译器如何处理它,特别是对于Derived
,但由于简单的vtable父指针不适用于多重继承,逻辑上编译器无法通过该机制来完成:需要一些额外的支持数据结构,RTTI信息。
" 我想知道如何向下转换,然后检查它是否是指向正确类型的指针。但是,我无法修改所涉及的类或打开RTTI。
如果您无法更改代码或启用RTTI,则通常无法获取所需信息。
在您控制所有对象实例化的特殊情况下,您原则上可以维护一个单独的每对象类型信息映射,但效率极低。
答案 1 :(得分:0)
如果编译器在运行时插入足够的数据以使dynamic_cast
工作,那么它们也会插入足够的RTTI来工作。如果您dynamic_cast
可以引用其他类型,则可以检查它是否是同一类型或其他类型的后代。因此,这与在默认情况下简单地打开RTTI相同。
作为为什么编译器可能想要关闭它以提高效率的一个例子,如果你的派生类没有覆盖其父项的任何虚函数,会发生什么?编译器可能希望它只是重用相同的虚函数表。它也不需要跟踪基础和派生关系来进行函数调度。