This was an interview question. Consider the following:
struct A {};
struct B : A {};
A a;
B b;
a = b;
b = a;
Why does b = a;
It's true that a B
is an A
, but an A
is not a B
, but this fact is only directly applicable when you're working with pointers or references to A
's and B
's. The problem here is your assignment operator.
struct A {};
struct B : A {};
Is equivalent to
struct A {
A& operator=(const A&);
};
struct B : A {
B& operator=(const B&);
};
So when you're assigning below:
A a;
B b;
a = b;
The assignment operator on a
can be called with an argument of b
, because a B
is an A
, so b
can be passed to the assignment operator as an A&
. Note that a
's assignment operator only knows about the data that's in an A
, and not the stuff in a B
, so any members of B that aren't part of A get lost - this is known as 'slicing'.
But when you're trying to assign:
b = a;
a
is of type A
, which is not a B
, so a
can't match the B&
parameter to b
's assignment operator.
You would think that b=a
should just call the inherited A& A::operator=(const A&)
, but this is not the case. The assignment operator B& B::operator=(const B&)
hides the operator that would be inherited from A
. It can be restored again with a using A::operator=;
declaration.