Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly implement polymorphism with base class pointers in C++?

I'm learning Object-Oriented Programming in C++ and trying to understand polymorphism with base class pointers.

I created a base class Animal and a derived class Dog, both with a speak() method. I expected that when I create a pointer of type Animal* and assign it to a Dog object, calling speak() would execute the Dog version. However, it always calls the base class version.

How can I achieve that ?

#include <iostream>
using namespace std;

class Animal {
public:
    void speak() {
        cout << "Animal sound" << endl;
    }
};

class Dog : public Animal {
public:
    void speak() {
        cout << "Woof!" << endl;
    }
};

int main() {
    Animal* a = new Dog();
    a->speak();  // Expected: Woof!, Actual: Animal sound
    return 0;
}
like image 675
Hassan Ali Avatar asked Aug 09 '26 23:08

Hassan Ali


1 Answers

You seem to expect that the method that is called will be determined on the actual runtime type of the object it is used with (here a Dog).

This is called runtime (or dynamic) dispatch and it is done in C++ only for virtual methods. In other words, you want Dog::speak to override Animal::speak, only virtual methods can be overidden.

For methods which are not virtual the call is determined at compile time, based on the type of the pointer (in your case Animal*) and not the actual object it points to.

A fixed version:

#include <iostream>

class Animal {
public:
//--vvvvvvv---------------
    virtual void speak() {
        std::cout << "Animal sound" << std::endl;
    }
};

class Dog : public Animal {
public:
//---------------vvvvvvvv--
    void speak() override {
        std::cout << "Woof!" << std::endl;
    }
};

int main() {
    Animal* a = new Dog();
    a->speak(); 
}

Output:

Woof!

Live demo - Godbolt

Notes:

  1. I also used the override specifier in the derived class which is recommended, in order to get the help of the compiler when you attempt to override a method that is not eligable for that. But stricktly speaking it is not a must (it is enough that the base method is marked virtual).

  2. a should be deleted, or even better: automatically managed by a smart pointer, e.g. std::unique_ptr:

    std::unique_ptr<Animal> a = std::make_unique<Dog>();
    a->speak();
    // `a` will be deallocated automatically
    

    Note: When deleting via a base class pointer, the base class destructor must also be virtual:

    class Animal {
    public:
        virtual ~Animal() = default; // <-----
    
        virtual void speak() {
            std::cout << "Animal sound" << std::endl;
        }
    };
    
  3. It is recommended to avoid using namespace std;. See: What's the problem with "using namespace std;"?.

like image 197
wohlstad Avatar answered Aug 13 '26 15:08

wohlstad



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!