1

I have declared a Super Class with a virtual print function and Child class inherits Super class. I have created an instance of Child Class and assigned to Super Class in 2 different ways.

#include <iostream>

using namespace std;

class Super
{
public:
    Super(){}
    virtual void print()
    {
    cout << "Super class is printing " << endl;
    }
};

class Child: public Super
{
public:
    Child(){}
    void print()
    {
        cout << "Child class printing" << endl;
    }
};

int main()
{
    Child c;
    Super s = c;
    Super &ss = c;
    s.print(); //prints "Super Class is printing
    ss.print(); //prints "Child Class is printing
    return 0;
}

Why we do not get same output from these two print calls ? How does adding reference change the behavior?

quamrana
  • 37,849
  • 12
  • 53
  • 71
bhavesh
  • 1,343
  • 2
  • 14
  • 23

2 Answers2

2

The dynamic and static type of s is Super but the assignment from c makes a copy of the Super subobject from inside c and s always behaves as a Super.

However, ss has a static type of Super, but its dynamic type depends on its initialisation, which in this case is Child, so the virtual dispatch behaves accordingly.

This phenomenon is called "object slicing"

quamrana
  • 37,849
  • 12
  • 53
  • 71
Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
1

The Object slicing issue:

If you take a super class and assign it the value of a subclass only the members that are part of the super class get copied over (default assignment operator behavior).

Consider the following:

#include <iostream>

using namespace std;

class Super {
public:
   int a;
   Super(): a(0) { }
   Super(int _a): a(_a) { }
   virtual void dump() {
        cout << "A is : " << a << std::endl;
   }
};

class Child: public Super {
public: 
   int b;

   Child(int _a, int _b): b(_b), Super(_a) { } 
   virtual void dump() {
        Super::dump();
        cout << "B is : " << b << std::endl;
   }

};

int main() {
    Child c(5, 10);
    Super s;
    s.dump();  // A is 0
    s = c;
    s.dump();  // A is 5 (but there is no B in s 
               // so calling Child::dump would be nonsensical
}

So as you can see that calling the child dump is nonsensical when the child value is assigned to the parent; because there is no "b" in the parent context.

Note that a statement like: c = s;

is non-sensical because while parentage is deterministic (Child is the type of Super so the implicit operator Super& Super::operator=(const Super&) applies to the derived Child class the reverse isn't true; i.e. Child& Child::operator=(const Child&) does not make sense in context of Super

The reference issue

Okay so the confusion comes in from understanding what a reference variable is. A reference variable is a synonym for whatever it is initialized with. You can use the reference variable exactly like the original.

In your case:

   ss.print(); 

is the same as

   c.print();

" To see this more explicitly, consider the following snippet:

int foo;
int& bar = foo;

// bar is now a reference to foo so the following will sets foo to 67
bar = 67;
std::cout << foo <<std::endl;
Ahmed Masud
  • 21,655
  • 3
  • 33
  • 58
  • 1
    *A bit pedantic*: "A reference variable is a synonym for whatever is assigned to it" No, *for whatever you initialized it with*. It has nothing to do with an actual *assignment*, even though it may use a `=` like in your example. Some other ways to initialize a reference: `int& bar{foo};` (C++11) and `int& bar(foo)`. – dyp Aug 03 '13 at 18:17
  • An even better term for the process of creating a reference is *binding*, and then one can talk about the object it is *bound to*. – Ben Voigt Aug 03 '13 at 18:36
  • @DyP Nuanced :-) I'll fix the answer. – Ahmed Masud Aug 03 '13 at 18:41