c++polymorphismvirtual-functions

Base class method not called on object of derived type: polymorphism without pointer and reference


Consider a Base class and a derived class that inherits from it called Child. Assume the Base class has a member function declared virtual, and that Child overrides that function. I would like to declare a variable as a Base class object, initialize it using the Child derived class constructor, and then use the Child class version of the member function. In other words, the following C++ program:

#include <iostream>

class Base {
public:
    virtual int give_number(int x) { return x; }
};

class Child : public Base {
public:
    int give_number(int x) { return x+1; }
};

int main() {
    Base base;
    Child child;
    Base child2;
    child2 = Child();
    std::cout << "Base says " << base.give_number(1) << "\n";
    std::cout << "Child says " << child.give_number(1) << "\n";
    std::cout << "Child2 says " << child2.give_number(1) << "\n";
}

results in the following output:

Base says 1
Child says 2
Child2 says 1

But I would instead prefer the following output:

Base says 1
Child says 2
Child2 says 2

Is there a way to accomplish this?


Solution

  • In the statement:

    child2 = Child();
    

    You are slicing the Child object, which is why the Child::give_number() method is not being called. child2 is a Base instance, never a Child instance. During the assignment, only the Base portion of the new Child object is copied into child2.

    You must use a pointer or reference when calling a virtual method polymorphically, eg:

    #include <iostream>
    
    class Base {
    public:
        virtual ~Base() = default;
        virtual int give_number(int x) { return x; }
    };
    
    class Child : public Base {
    public:
        int give_number(int x) override { return x+1; }
    };
    
    int main() {
        Base base;
        Child child;
        Child child2;
        Base& base2 = child2;
        std::cout << "Base says " << base.give_number(1) << "\n";
        std::cout << "Child says " << child.give_number(1) << "\n";
        std::cout << "Base2 says " << base2.give_number(1) << "\n";
    }
    

    Or:

    #include <iostream>
    
    class Base {
    public:
        virtual ~Base() = default;
        virtual int give_number(int x) { return x; }
    };
    
    class Child : public Base {
    public:
        int give_number(int x) override { return x+1; }
    };
    
    int main() {
        Base base;
        Child child;
        Child child2;
        Base* base2 = &child2;
        std::cout << "Base says " << base.give_number(1) << "\n";
        std::cout << "Child says " << child.give_number(1) << "\n";
        std::cout << "Base2 says " << base2->give_number(1) << "\n";
    }
    

    Or:

    #include <iostream>
    #include <memory>
    
    class Base {
    public:
        virtual ~Base() = default;
        virtual int give_number(int x) { return x; }
    };
    
    class Child : public Base {
    public:
        int give_number(int x) override { return x+1; }
    };
    
    int main() {
        Base base;
        Child child;
        //Base* child2 = new Child;
        std::unique_ptr<Base> child2 = std::make_unique<Child>();
        std::cout << "Base says " << base.give_number(1) << "\n";
        std::cout << "Child says " << child.give_number(1) << "\n";
        std::cout << "Child2 says " << child2->give_number(1) << "\n";
        //delete child2;
    }