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).