I am learning c++ on my own and have encountered a behavior I did not expect. I am unsure but do think this is not what Java would do in a similar situation. Why are the Dog
and the Cat
relying on te parent class implementation and making a generic sound?
#include <iostream>
class Animal{
public:
virtual void speak(){std::cout << "???" << std::endl; /* not implemented */}
};
class Dog : public Animal{
public:
virtual void speak(){
std::cout << "Woof" << std::endl;
}
};
class Cat : public Animal{
public:
virtual void speak(){
std::cout << "Meow" << std::endl;
}
};
class Desk{
/* Not an animal */
};
template<class T>
void please_talk(){
T anim;
Animal ani = anim;
anim.speak();
ani.speak();
}
int main()
{
please_talk<Dog>();
please_talk<Cat>();
/* Does not compile please_talk<Desk>(); */
return 0;
}
Result:
Woof
Generic animal sound
Meow
Generic animal sound
Animal ani = anim;
That creates a new object of type Animal
, regardless of the type of anim
. So ani.speak()
will call Animal::speak
, since that is the override for type Animal
.
If you were to create a reference (or pointer)
Animal & ani = anim;
then the dynamic type would be preserved, and T::speak
would be called. This is similar to what happens in Java when you copy an object reference; but you should not try to understand the C++ object model in terms of Java's since they are very different.
You can prevent accidental creation of base-class objects (sometimes known as "slicing", since it slices off the derived-class parts of an object) by making the base class abstract. That is, declare the function pure virtual, rather than non-pure with a default implementation:
virtual void speak() = 0; // Really not implemented
Abstract classes can't be instantiated as a complete object, so this will cause a compile-time error if you try to.