考虑以下:
B继承自A并覆盖打印功能.
A有一个静态函数,它取一个void*,将它转换为A并调用虚拟打印函数.
如果void*最初是B,它会调用A :: print还是B :: print?
#includeclass A { public: static void w(void *p) { A *a = reinterpret_cast(p); a->print(); } virtual void print() { std::cout << "A" << std::endl; } }; class B : public A { public: void print() { std::cout << "B" << std::endl; } }; int main () { B b; A::w(&b); }
这为我打印B.
似乎已经转换为A的void*仍然知道B被覆盖的打印功能.原因不是立即清楚.
有人可以向我解释这是否是我可以依赖的行为,或者它是否只是一些有效的因为它是一个小例子(比如返回对局部变量的引用并不总是在小程序中段错误).
您的代码具有未定义的行为
§5.2.10重新解释演员
7将"指向T1的指针"类型的prvalue转换为"指向T2的指针"类型(其中T1和T2是对象类型,T2的对齐要求不比T1更严格)并返回其原始类型会产生原始指针值.未指定任何其他此类指针转换的结果.
虚函数通常由隐式求解vtable
.这基本上是类层次结构中每个虚函数的函数指针数组.编译器将其添加为您的类的"隐藏成员".调用虚函数时,调用vtable中的相应条目.
现在,当您创建一个类型的类时B
,它隐式地将B-vtable存储在对象中.强制转换不会影响此表.
因此,当你投射void *
到时A
,原始的vtable(类B
)存在,指向B::print
.
请注意,这是实现定义的行为,标准不保证这一点.但大多数编译器都会这样做