以下示例会发生什么?
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不是......为什么?
答案 0 :(得分:11)
x
引用B
的{{1}}基类子对象。作业d
slices来自x = d2
的{{1}}基础子对象,并将其值分配给B
的子对象。
通常不会故意这样做。
修改强>
似乎x.x已更新,但vftable不是......为什么?
这就是赋值运算符d2
的作用。 C ++中的基类完全没有意识到它们是基类。此外,在其生命周期内不能改变对象的类型。最接近的替代方案是C ++ 11的d
,它可以将B::operator=
内的旧std::move
对象转移到新的B
对象中。然后你会破坏旧的对象。
答案 1 :(得分:3)
如果需要,可以自己实现=并通过检查适当的具体类型(或给出错误)来“避免”切片。请参阅下面的示例,其中包含错误。
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;
}
};
答案 2 :(得分:1)
在您的情况下,当您分配此方式时,将不会切换不属于Base类的成员。这意味着,在这种情况下,它被复制,就像你将一个Base类对象分配给另一个。