为什么对基类的赋值有效,但是对派生类的赋值是编译错误?

max*_*yne 38 c++ inheritance compiler-errors

这是一个面试问题.考虑以下:

struct A {}; 
struct B : A {}; 
A a; 
B b; 
a = b;
b = a; 
Run Code Online (Sandbox Code Playgroud)

为什么b = a;抛出错误,虽然a = b;完全没问题?

Joh*_*itb 62

因为隐式声明的复制赋值运算符B隐藏了隐式声明的复制赋值运算符A.

所以对于线b = a,只有在operator=B是一个候选人.但是它的参数有类型B const&,不能通过A参数初始化(你需要一个向下转换).所以你得到一个错误.

  • 您可以尝试将`B`的定义更改为`struct B:A {using A :: operator =; 并且观察两行都将编译. (14认同)

use*_*016 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;
Run Code Online (Sandbox Code Playgroud)

在你的榜样,没有属性someInt,也没有anotherInt,所以它可以工作.但无论如何编译器都不会允许它.

  • -1:从哲学上讲,你的答案是正确的,但是当你使用指针来引用对象时,哲学只能直接转换成代码.关于隐含的"A :: operator ="和"B :: operator ="缺少一些技术细节,其他答案覆盖得更好. (8认同)

Ken*_*oom 6

确实a B是a A,但是a A不是a B,但是当你使用指针或对As和Bs的引用时,这个事实才直接适用.这里的问题是你的赋值运算符.

struct A {}; 
struct B : A {};
Run Code Online (Sandbox Code Playgroud)

相当于

struct A {
   A& operator=(const A&);
}; 
struct B : A {
   B& operator=(const B&);
};
Run Code Online (Sandbox Code Playgroud)

所以当你在下面分配时:

A a; 
B b; 
a = b;
Run Code Online (Sandbox Code Playgroud)

a可以使用参数of来调用赋值运算符on b,因为a B是a A,因此b可以作为a传递给赋值运算符A&.请注意,a赋值运算符只知道a中的数据,A而不知道a中的东西B,因此B中不属于A的任何成员都会丢失 - 这称为"切片".

但是当你试图分配时:

b = a; 
Run Code Online (Sandbox Code Playgroud)

a是类型A,不是a B,因此a无法将B&参数与b赋值运算符匹配.

你会认为b=a应该只调用继承A& A::operator=(const A&),但事实并非如此.赋值运算符B& B::operator=(const B&)隐藏了将继承的运算符A.它可以通过using A::operator=;声明再次恢复.