Learning C++: polymorphism and slicing
Animal badDog = Dog();
ad.makeSound();
When you instantiate a Dog
and assign it by-value to an Animal
variable, you slice the object. Which basically means you strip off all the Dog
-ness from badDog
and make it in to the base class.
In order to use polymorphism with base classes, you must use either pointers or references.
This is a problem called "slicing."
Dog()
creates a Dog
object. If you were to call Dog().makeSound()
, it would print "bark" as you expect it to.
The problem is that you are initializing the badDog
, which is an object of type Animal
, with this Dog
. Since the Animal
can only contain an Animal
and not anything derived from Animal
, it takes the Animal
part of the Dog
and initializes itself with that.
The type of badDog
is always Animal
; it can never be anything else.
The only way you can get polymorphic behavior in C++ is using pointers (as you have demonstrated with your goodDog
example) or using references.
A reference (e.g., Animal&
) can refer to an object of any type derived from Animal
and a pointer (e.g., Animal*
) can point to an object of any type derived from Animal
. A plain Animal
, however, is always an Animal
, nothing else.
Some languages like Java and C# have reference semantics, where variables are (in most cases) just references to objects, so given an Animal rex;
, rex
is really just a reference to some Animal
, and rex = new Dog()
makes rex
refer to a new Dog
object.
C++ doesn't work that way: variables don't refer to objects in C++, variables are objects. If you say rex = Dog()
in C++, it copies a new Dog
object into rex
, and since rex
is actually of type Animal
, it gets sliced and just the Animal
parts get copied. These are called value semantics, which are the default in C++. If you want reference semantics in C++, you need to explicitly use references or pointers (neither of these are the same as references in C# or Java, but they are more similar).