#include <cstdio>
#include <cstring>
class A
{
public:
virtual void foo()
{
puts("A");
}
};
class B : public A
{
public:
void foo()
{
puts("B");
}
};
int main()
{
A a;
B b;
memcpy(&a, &b, sizeof (b));
(&a)->foo();
}
答案 0 :(得分:9)
在non-POD类型上执行原始内存操作(例如memcpy
)会调用未定义的行为。你不应该这样做!
答案 1 :(得分:4)
你不应该像那样混淆非POD类型。特别是,C ++标准说memcpy
非POD导致未定义的行为,在您的情况下,显示为继续a
为A
类型。
在您的特定情况下,编译器“知道”a
的“静态类型”和“动态类型”都是A
(因为其类型不能“合法地”更改 - 你的技巧是非法的,所以没有执行虚拟调度,但是直接调用a.foo()
(因此你覆盖vptr的技巧没有效果)。
答案 2 :(得分:3)
因为你对memcpy
的任何和所有保证都非常粗暴,并且很幸运能得到任何行为。按照你的意愿使用赋值运算符!
答案 3 :(得分:3)
因为 - 为什么要这样?编译器发现a
不是指针或引用,因此除foo
的原始实现之外不能调用任何内容。编译器不打扰使调用成为虚拟(因为这是不必要的昂贵)。
正如Oli所说,你的字节副本会引发未定义的行为。一切顺利。
答案 4 :(得分:0)
memcpy(&a, &b, sizeof (b));
(&a)->foo();
这是undefined behavior。这保证仅适用于POD - 类型。所以... UB是UB。不用惊讶
答案 5 :(得分:0)
A a;
B b;
memcpy(&a, &b, sizeof (b));
如果A有成员,您将在此代码中遇到访问冲突。 正确的方法是下一步:
A a;
B b;
A *c = &a;
c->foo(); //A::foo()
c = &b;
c->foo(); //B::foo()