Reputation: 33
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
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
Reputation: 597205
Your code suffers from two problems:
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.
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
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
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