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).
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.
You initialized badDog using the assignment operator. Thus Dog() was copied as Animal. The output of your program is correct. :)