Question

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
Was it helpful?

Solution

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.

OTHER TIPS

This line Animal ani = anim; creates a generic animal from the specific animal. It's called slicing as you lost the original derived class.

You need to change it to a reference or a pointer:

Animal& ani = anim;

Animal* pAni = &anim;

This is all because you have actual object of Animal class instead of pointer or reference to animal class. So If you want the speak() method of dog and Cat to be called them make reference or pointer of parent class Animal. Otherwise you will get speak() method of animal called as methods are called according to actual object instead of references in polymorphism.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top