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

61 Views Asked by At

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?

1

There are 1 best solutions below

0
Remy Lebeau On BEST ANSWER

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;
}