10

This surprised me a little bit, but I was playing around with some code and found out that, at least on my computer, when a function accepts a parent class by reference and you pass a child instance, that the slicing problem doesn't occur. To illustrate:

#include <iostream>

class Parent
{
public:
    virtual void doSomething()
    {
        using namespace std;
        cout << "Parent::DoSomething" << endl;
    }
};

class Child : public Parent
{
public:
    virtual void doSomething()
    {
        using namespace std;
        cout << "Child::DoSomething" << endl;
    }
};

void performSomething(Parent& parent)
{
    parent.doSomething();
}

int main(int argc, char** argv)
{
    Child myChild;

    performSomething(myChild);

    return 0;
}

This prints out Child::DoSomething.

Like I said, I was a little surprised. I mean, I know that passing by reference is like passing pointers around (but much safer in my understanding), but I didn't know I still got to keep polymorphic goodness when doing so.

I just want to make sure, is this supposed to happen or is it one of those "it works on my machine" type of instances?

Anthony
  • 9,451
  • 9
  • 45
  • 72
  • That's not what "slicing" is. Also, does that code even compile? What is `using std;`? – Kerrek SB Nov 26 '11 at 13:43
  • Meant it to be `using namespace std`. I figured I was able to get the point across, but cleaned up the code for overall benefit to the site. – Anthony Nov 26 '11 at 13:49

4 Answers4

13

"Slicing" refers to the inability of the base copy constructor to distinguish exact type matches from derived classes. The only way to invoke slicing is to invoke the base copy constructor. Typically this occurs when passing arguments by value, though other situations can be contrived:

class Base { };
class Derived : public Base { };

void foo(Base);

int main()
{
  Derived x;

  Base y = x;   // flagrant slicing
  foo(x);       // slicing by passing by value
}

You're never doing any such thing, so you do not encounter any slicing situations.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 2
    Mention the copy constructor when passing by value is what make this answer perfect. – dani Feb 27 '15 at 17:00
9

The behavior you are seeing is correct. This is how it is supposed to work. References work just like pointers.

trenki
  • 7,133
  • 7
  • 49
  • 61
  • Thanks, that's what I figured. Like I mentioned, I just wanted a sanity check so I didn't make invalid assumptions. – Anthony Nov 26 '11 at 13:50
3

That's supposed to happen. Passing by reference is EXACTLY like passing pointers -- it's doing the same thing under the hood. There's no magic to this; every instance of a polymorphic object has a virtual function table associated with it. As long as you don't copy anything, you're not going to lose that information and your virtual function calls will work the way you expect they would.

The reason that you run into problems when passing by value is that it will use the copy constructor of the type you specified in the function signature, so you end up with an entirely new instance of the superclass.

Nathan Monteleone
  • 5,430
  • 29
  • 43
2

Yes, binding to a reference enables dynamic binding. This is caused by the difference of the dynamic type of an object and its static type.

If you take your parameter by value, it becomes a Parent class. Although if you pass something through a reference or a pointer and call a virtual function, the run-time will look for the dynamic type or most-derived type of the actual object that is being referenced.

pmr
  • 58,701
  • 10
  • 113
  • 156