Consider the following example:
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void makeSound() {cout << "rawr" << endl;}
};
class Dog : public Animal
{
public:
virtual void makeSound() {cout << "bark" << endl;}
};
int main()
{
Animal animal;
animal.makeSound();
Dog dog;
dog.makeSound();
Animal badDog = Dog();
badDog.makeSound();
Animal* goodDog = new Dog();
goodDog->makeSound();
}
The output is:
rawr
bark
rawr
bark
But I thought that surely the output should be "rawr bark bark bark". What's with the badDog?
Update: You may be interested in another question of mine.
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).