【发布时间】:2017-04-26 22:13:22
【问题描述】:
我正在阅读深入了解 C++ 对象模型。在第 1.3 节中
那么,既然如此,为什么会这样呢
Bear b;
ZooAnimal za = b;
// ZooAnimal::rotate() invoked
za.rotate();
调用的 rotate() 实例是 ZooAnimal 实例而不是 Bear 的实例?此外,如果按成员初始化将一个对象的值复制到另一个对象,为什么 za 的 vptr 不寻址 Bear 的虚拟表?
第二个问题的答案是编译器在一个类对象与另一个类对象的初始化和赋值中进行了调解。编译器必须确保如果一个对象包含一个或多个 vptr,源对象不会初始化或更改这些 vptr 值。
于是我写了下面的测试代码:
#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;
}
Base::vfunc()
Base::vfunc()
sizeof Base : 4
Derived::vfunc()
b_assign: 80487b4; b_memcpy: 8048780; b_ref: 8048780
我的问题是为什么 b_memcpy 仍然调用 Base::vfunc()
【问题讨论】:
-
我想答案是反汇编,提示是
&b_memcpy == &b_ref -
行为未定义。使用不同的编译器、不同的编译器选项、优化等,您看到的任何结果都很容易不同。
-
我把测试代码改成了this,结果和我预期的一样。
-
@PaulMcKenzie vptr 甚至不正式存在,因此对 vptr 的任何操作都将是未指定的或 UB。不过,只要我们可以合理地声称没有违反规则,一些操作应该会起作用。
标签: c++ undefined-behavior lifetime dynamictype vptr