以下示例中会发生什么?
struct B { };
struct D1 : B { };
struct D2 : B { };
int main()
{
D1 d;
D2 d2;
B& x = d;
x = d2;
}
我知道引用没有重新分配。 x
还是指 d
,但是你怎么能分配 d2
至 d
?
多一点:
struct B
{
B () { x = 0; }
int x;
virtual void foo () { cout << "B" << endl; }
};
struct D1 : B
{
D1 () { x = 1; }
virtual void foo () { cout << "D1" << endl; }
};
struct D2 : B
{
D2 () { x = 2; }
virtual void foo () { cout << "D2" << endl; }
};
int main()
{
D1 d;
D2 d2;
B& x = d;
x.foo(); //D1
//x.x is 1 here
x = d2;
x.foo(); //also D1
//but x.x is 2 here
}
这好像是 x.x
更新了,但vftable不是......为什么?
x
是指 B
基类 子对象 的 d
。分配 x = d2
片 该 B
基础子对象来自 d2
并将其值分配给子对象 d
。
这通常不是故意做的。
编辑:
似乎x.x已更新,但vftable不是......为什么?
这就是赋值运算符 B::operator=
确实。 C ++中的基类完全没有意识到它们是基类。此外,在其生命周期内不能改变对象的类型。最接近的选择是C ++ 11 std::move
,这可以转移旧 B
里面的物体 D1
变成新鲜的 D2
目的。然后,您将销毁旧对象。
如果需要,可以自己实现=并通过检查适当的具体类型(或给出错误)来“避免”切片。请参阅以下带错误的示例。
struct B {
virtual B& operator = (B& b) = 0;
};
struct D1 : B {
D1& operator = (B& b) {
if ( dynamic_cast<D1*>(&b) == 0 ) {
cerr << "Cannot assign non D1 to D1" << endl;
exit(255);
}
// handle the assignments
return *this;
}
};
struct D2 : B {
int c;
D2& operator = (B& b) {
if ( dynamic_cast<D2*>(&b) == 0 ) {
cerr << "Cannot assign non D2 to D2" << endl;
exit(255);
}
// handle the assignments
return *this;
}
};
在您的情况下,当您分配这种方式时,不会属于Base类的成员将被切片。这意味着,在这种情况下,它被复制,就像你将一个Base类对象分配给另一个。