2

I am reading a book which says:

pass-by-value doesn't work if the function you're sending the argument to has a parameter type which is an abstract base class (ABC). You have to pass the argument (which would be a derived class) by reference.

My questions are:

Why can you not pass the derived class argument by value?

Is there something "internal" to C++ which requires it to be a reference?

Is this to do with the way dynamic binding works?

taocp
  • 23,276
  • 10
  • 49
  • 62
user997112
  • 29,025
  • 43
  • 182
  • 361
  • You could also use a pointer. – chris Jun 01 '13 at 20:37
  • http://en.wikipedia.org/wiki/Object_slicing – Lee Jun 01 '13 at 20:38
  • 1
    Abstract classes can't be instantiated, so "obviously" you can't pass them by value. Also, pass-by-value doesn't play well with inheritance ([slicing problem](http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c)). – syam Jun 01 '13 at 20:39
  • Unlike some C/C++ derived languages (like C# and Java), C++ can have variables refer to actual instances of objects, instead of references to objects. These actual instances both obey value semantics, and have a fixed at compile time binary layout and size. This blocks (direct) polymorphism. If you need value semantics with polymorphism, the `pImpl` pattern and type erasure (like how `std::function<>` works) can be used to create non-polymorphic objects with polymorphic runtime behavior. – Yakk - Adam Nevraumont Jun 01 '13 at 21:15

4 Answers4

7

This is because of object slicing: the abstract class received by value will receive a copy of the object that you are passing; therefore, the derived data members will be sliced off from it, making the object unusable.

When you pass by reference, you are passing the address of the existing object, which is a member of a derived class, all its data members included. This is not specific to C++ - this is a property of passing by value in general.

The dynamic binding is implemented in such a way as to not allow sliced instance receive calls as if it were a complete instance. The vtable pointer is adjusted to dispatch the calls to the member functions of the abstract base class.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
6

Why can you not pass the derived class argument by value?

Simply put, if you have a function that looks like this:

void foo(T t); // Takes a T by value

And you call it this way (whatever v is):

foo(v);

What happens is that the parameter t represents a new object which is copy-initialized from the argument v, as if you were doing:

T t = v;

Now if T is abstract, the above is illegal, because you cannot instantiate an abstract class (by definition). Therefore, the parameter of foo() cannot be copy-initialized from its argument.

Is there something "internal" to C++ which requires it to be a reference?

Something like that. Dynamic polymorphism in C++ can only work through references and pointers. When you try to assign an object of a derived class to an object of a base class, what you get is object slicing.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
3

You can pass a derived class by value. You cannot pass the abstract base class as an argument by value because there is no way to instantiate an abstract class.

In general you want to pass by reference or pointers so you do not slice the object. There is a good answer here: What is object slicing?

Community
  • 1
  • 1
Guillaume
  • 2,044
  • 12
  • 11
0

When you receive an object by value, its dymanic (its "real" type) type is its static type. It is not possible to have a variable whose dynamic type is an abstract one. No matter how you build it.

Elazar
  • 20,415
  • 4
  • 46
  • 67