4

When I try this code the output I get is

1 1 | 1 2

However if I get rid of the reference, i.e.

// replace 
A& a_ref = b2;  
a_ref = b1;
// with 
b2 = b1;

the output changes to

1 1 | 1 1

and I cant find any website that explains why this happens. Can any one explain it?

#include <iostream>
struct A {
 int foo;
};
struct B : public A {
 int bar;
 B(int x,int y) : bar(y) { this->foo=x; }
};
int main(void) {
 B b1(1,1), b2(2,2);
 A& a_ref = b2;
 a_ref = b1;
 std::cout << b1.foo << ' ' << b1.bar << " | " << b2.foo << ' ' <<
b2.bar << '\n';
 return 0;
}
cigien
  • 57,834
  • 11
  • 73
  • 112
  • 3
    You assign to `A` subobject of `b2` object. `b1` is implicitly converted to `A`, since the type of the left-hand side is `A`. In other words, the assignment is equivalent to `a_ref = (A&)b1;`. – Igor Tandetnik Jul 04 '20 at 18:18
  • 1
    Further reading: [What is object slicing?](https://stackoverflow.com/q/274626/501250) – cdhowie Jul 04 '20 at 18:46

2 Answers2

2

When you do:

A& a_ref = b2; 

the reference a_ref is only referring to the members of B that are inherited from A. An A& can't know about the members of derived classes after all.

So when you do:

a_ref = b1;

the only members that are copied to a_ref are the members it knows about, which is only foo. So only b2.foo changes.

In this case:

b2 = b1;

You are copying all the members of a B object, so all the members get changed.

cigien
  • 57,834
  • 11
  • 73
  • 112
2

You are using a A reference, it could be tied to any derived type (same explanations holds true for pointers). The compiler allows tying it to any object so you can forget about its exact type, be it A, B, as long as it inherits from A. Obviously it doesn't know about the internals of any derived type, which is why it just does A things.

This may be handled using virtual functions; in that case, the compiler takes care of putting a table with pointers to the real functions (not just those in the base type). As those functions share their signature, a caller can call any of them, not caring about what happens inside.

This said, you could define a virtual copy assignment operator, which would do what you expect... or maybe not!

I was fooled and thought you could, but you really can't... See virtual assignment operator C++ to know why.

olepinto
  • 351
  • 3
  • 8