Logarithm
Logarithm

Reputation: 33

When I call a function in child class it is instead calling the parent class function

I am working on a project where I have an array of children classes. I want to call an overridden child function from the array, but instead it calls the parent function.

#include <iostream>

class Parent {
public:
    Parent(){}
    void print() {
        std::cout << "I'm the parent!" << std::endl;
    }
};

class ChildOne : public Parent {
public:
    ChildOne(){}
    void print() {
        std::cout << "I'm childOne!" << std::endl;
    }
};

class ChildTwo : public Parent {
public:
    ChildTwo() {}
    void print() {
        std::cout << "I'm childTwo!" << std::endl;
    }
};


int main(int argc, char const *argv[]) {
    Parent arr[] = {ChildOne(), ChildTwo()};
    int n = 2;

    for(int i = 0; i < n; i++) {
        arr[i].print();
    }

    return 0;
}

The output I get is

I'm the parent!
I'm the parent!

Where the output I want is

I'm childOne!
I'm childTwo!

Upvotes: 3

Views: 1534

Answers (4)

Peter
Peter

Reputation: 36617

Firstly, the member function of Parent needs to be virtual.

class Parent
{
   public:
       Parent(){}
       virtual void print() {std::cout << "I'm the parent!" << std::endl;};
};

Then the children need to override it. In C++11 and later, it is advisable to use override

class ChildOne : public Parent
{
   public:
      ChildOne(){}
      void print() override {std::cout << "I'm childOne!" << std::endl;};
};

The second thing to address is that your code in main()

Parent arr[] = {ChildOne(), ChildTwo()};

initialises two Parent objects by slicing i.e. arr[0] and arr[1] are both of type Parent, not of ChildOne or ChildTwo respectively.

To address that is it necessary that arr be an array of pointers, and initialised accordingly.

 Parent *arr[] = {new ChildOne(), new ChildTwo()};

which can be followed up with

for(int i = 0; i < 2; i++)
{
    arr[i]->print();
}

for(int i = 0; i < 2; i++)    // to avoid a memory leak
{
    delete arr[i];
}
//  don't use elements of `arr` here

A better way (C++11 and later) is to write main() is to use std::unique_ptr from the standard header <memory>)

std::unique_ptr<Parent> arr[] = {new ChildOne(), new ChildTwo()};

which allows doing away with the loop to release the elements of arr. In C++14 and later, the objects in arr can be created using std::make_unique().

Upvotes: 5

Remy Lebeau
Remy Lebeau

Reputation: 597205

Your code suffers from two problems:

  1. you are not actually overriding print() at all, because it is not virtual. So you are merely overloading it in each child class, hiding the parent's method.

  2. you are slicing your objects when storing them into your array. So, it doesn't matter if print() is virtual, since there are no child objects in the array, only parent objects. Polymorphism works correctly only when using pointers/references to base classes.

Try this instead:

#include <iostream>

class Parent {
public:
    Parent(){}
    virtual void print() {
        std::cout << "I'm the parent!" << std::endl;
    }
};

class ChildOne : public Parent {
public:
    ChildOne(){}
    void print() override {
        std::cout << "I'm childOne!" << std::endl;
    }
};

class ChildTwo : public Parent {
public:
    ChildTwo() {}
    void print() override {
        std::cout << "I'm childTwo!" << std::endl;
    }
};

int main() {
    ChildOne c1;
    ChildTwo c2;
    Parent* arr[] = {&c1, &c2};

    int n = 2;
    for(int i = 0; i < n; i++) {
        arr[i]->print();
    }

    return 0;
}

Upvotes: 2

fish2000
fish2000

Reputation: 4435

You're implicitly casting all your instances to type Parent when you store them in that typed array. Since you are using static dispatch, you're always going to call the method on the base type you've (implicitly) downcasted to.

Upvotes: 4

Stephen
Stephen

Reputation: 1528

You'll need to specify the parent function as virtual, and the child functions should utilize the override keyword.

class Parent {
public:
    Parent(){}
    virtual void print() {
        std::cout << "I'm the parent!" << std::endl;
    }
};

class ChildOne : public Parent {
public:
    ChildOne(){}
    void print() override {
        std::cout << "I'm childOne!" << std::endl;
    }
};

class ChildTwo : public Parent {
public:
    ChildTwo() {}
    void print() override {
        std::cout << "I'm childTwo!" << std::endl;
    }
};

Upvotes: 1

Related Questions