我正在阅读C++对象模型中的。在第1.3节中
Bear b;
ZooAnimal za = b;
// ZooAnimal::rotate() invoked
za.rotate();
所以我在下面写了测试代码:#include <stdio.h>
class Base{
public:
virtual void vfunc() { puts("Base::vfunc()"); }
};
class Derived: public Base
{
public:
virtual void vfunc() { puts("Derived::vfunc()"); }
};
#include <string.h>
int main()
{
Derived d;
Base b_assign = d;
Base b_memcpy;
memcpy(&b_memcpy, &d, sizeof(Base));
b_assign.vfunc();
b_memcpy.vfunc();
printf("sizeof Base : %d\n", sizeof(Base));
Base &b_ref = d;
b_ref.vfunc();
printf("b_assign: %x; b_memcpy: %x; b_ref: %x\n",
*(int *)&b_assign,
*(int *)&b_memcpy,
*(int *)&b_ref);
return 0;
}
resultBase::vfunc()
Base::vfunc()
sizeof Base : 4
Derived::vfunc()
b_assign: 80487b4; b_memcpy: 8048780; b_ref: 8048780
我的问题是为什么b_memcpy仍称Base::vfunc()
最佳答案
您正在执行的操作在C++语言中是非法的,这意味着b_memcpy
对象的行为未定义。后者意味着任何行为都是“正确的”,您的期望是完全没有根据的。尝试分析未定义的行为没有太多意义-不应遵循任何逻辑。
实际上,您对memcpy
的操作很可能确实将Derived
的虚拟表指针复制到了b_memcpy
对象。您对b_ref
的实验证实了这一点。但是,当通过直接对象调用虚拟方法时(如b_memcpy.vfunc()
调用的情况),大多数实现会优化对虚拟表的访问,并执行对目标函数的直接(非虚拟)调用。该语言的形式规则规定,没有任何法律行动可以进行b_memcpy.vfunc()
调用以调度到Base::vfunc()
以外的任何其他对象,这就是为什么编译器可以用直接调用Base::vfunc()
来安全地替换此调用的原因。这就是为什么任何虚拟表操作通常不会对b_memcpy.vfunc()
调用产生影响的原因。