这是一个面试问题。请考虑以下事项:
struct A {};
struct B : A {};
A a;
B b;
a = b;
b = a;
为什么b = a;
会抛出错误,而a = b;
完全正常?
答案 0 :(得分:62)
因为隐式声明的B
复制赋值运算符隐藏了A
的隐式声明的复制赋值运算符。
因此对于行b = a
,只有operator=
的{{1}}才是候选人。但是它的参数有B
类型,不能用B const&
参数初始化(你需要一个向下转换)。所以你得到一个错误。
答案 1 :(得分:24)
因为每个B都是A,但不是每个A都是B。
在评论之后编辑以使事情更清楚(我修改了你的例子):
struct A {int someInt;};
struct B : A {int anotherInt};
A a;
B b;
/* Compiler thinks: B inherits from A, so I'm going to create
a new A from b, stripping B-specific fields. Then, I assign it to a.
Let's do this!
*/
a = b;
/* Compiler thinks: I'm missing some information here! If I create a new B
from a, what do I put in b.anotherInt?
Let's not do this!
*/
b = a;
在您的示例中,没有属性someInt
或anotherInt
,因此可以工作。但无论如何编译器都不会允许它。
答案 2 :(得分:6)
B
确实是A
,但A
不是B
,但这一事实只有在您使用指针时才能直接应用或对A
和B
的引用。这里的问题是你的赋值运算符。
struct A {};
struct B : A {};
相当于
struct A {
A& operator=(const A&);
};
struct B : A {
B& operator=(const B&);
};
所以当你在下面分配时:
A a;
B b;
a = b;
可以使用a
参数调用b
上的赋值运算符,因为B
是A
,因此b
可以传递给A&
赋值运算符为a
。请注意,A
的赋值运算符只知道B
中的数据,而不知道b = a;
中的数据,因此B的任何成员都不属于A丢失 - 这被称为'切片'。
但是当你试图分配时:
a
A
的类型为B
,不是a
,因此B&
无法将b
参数与b=a
匹配的任务操作员。
您会认为A& A::operator=(const A&)
应该只调用继承的B& B::operator=(const B&)
,但事实并非如此。赋值运算符A
隐藏了将从using A::operator=;
继承的运算符。可以使用{{1}}声明再次恢复。
答案 3 :(得分:4)
我已经更改了结构的名称,使其显而易见:
struct Animal {};
struct Bear : Animal {};
Animal a;
Bear b;
a = b; // line 1
b = a; // line 2
显然,任何熊都是动物,但不是每一只动物都可以被认为是熊。
因为每个B“isa”A,B的任何实例也必须是A的实例:根据定义,它具有与A的任何其他实例相同顺序的相同成员。将b复制到a中会丢失B特定的成员,但完全填充结果成员满足A的要求A.另一方面,复制a到b可能会留下b不完整,因为B可能有比A更多的成员。这里很难看到因为A和B根本没有任何成员,但这就是编译器允许一个赋值而不允许另一个赋值的原因。
答案 4 :(得分:3)
请记住,如果没有显式声明的复制赋值运算符,则将为任何类隐式声明和定义(并且结构是C ++中的类)。
对于struct A
,它将具有以下签名:
A& A::operator=(const A&)
它只是执行其子对象的成员分配。
a = b;
没问题,因为B
会与const A&
的{{1}}参数匹配。由于只有A::operator=(const A&)
的成员被“成员分配”到目标,因此A
中不属于B
的任何成员都会丢失 - 这称为“切片”。
对于A
,implcit赋值运算符将具有以下签名:
struct B
B& B::operator=(const B&)
不正常,因为b = a;
与A
参数不匹配。
答案 5 :(得分:1)
如果我接受采访,我将以一点哲学的方式解释。
a = b;
有效,因为每个B
都包含A
。因此a
可以从A
中提取B
。但是,A
不包含B
。因此b
无法在B
内找到A
;这就是原因,
b = a;
无效。
[类似地,void*
可以找到Type*
,但在Type*
中找不到void*
(因此我们需要演员)。]