Let's say I have a set of following classes:
class animal
{
// members, constructors and other methods...
public:
virtual void what_do_you_eat() { cout << "i eat generic food" << endl; }
}
class cat : public animal
{
// members, constructors and other methods...
public:
void what_do_you_eat() { cout << "i eat cat food" << endl; }
}
class dog : public animal
{
// members, constructors and other methods...
public:
void what_do_you_eat() { cout << "i eat dog food" << endl; }
}
and I want to create a list (any container would be fine, but let's choose std::list<>
for this example):
std::list<animal> animals
animals.push_back( dog() );
animals.push_back( cat() );
but when I try to iterate over the list I get this output:
for(auto itr : animals)
{
itr.what_do_you_eat();
}
// output:
// i eat generic food
// i eat generic food
// i eat generic food
// i eat generic food
// ...
I tried then to make a list of pointers ( std::list<animal *> animals
), output was correct, but there are many issues with this solution:
std::list<animal * const> animals
and pointers held by animals
can be overwritten anywhere in my program. Question:
Is there any possibility to pass a derived class into an stl container, through a reference to a base class, and still get the right output?
Is there any workaround to do this correctly without pointers? Currently, I am writing a project that depends heavily on class inheritance, and I am stuck right now because I need to create a list of objects of different types (all of these types inherit directly or indirectly from a single base class) and it seems to be impossible.
solutions involving boost
library are acceptable.
When you are handling polymorphism container must use pointers of any kind. It is best to use smart pointer and in your case std::unique_ptr
will do the job perfectly.
So for example:
std::list<std::unieque_ptr<animal>> animals;
animals.emplace_back(new dog {});
animals.emplace_back(new cat {});
Note base class animal
has to have a virtual destructor! It is best to define this as an abstract class:
class animal
{
// NO members, NO constructors only pure virtual methods
public:
virtual ~animal() {};
virtual void what_do_you_eat() = 0;
};
In your code, list<animal>
should be list<animal*>
and then you must change other lines of the code accordingly.
See the code below. It works as you expected.
class animal
{
// members, constructors and other methods...
public:
animal(){}
virtual ~animal(){}
virtual void what_do_you_eat() { cout << "i eat generic food" << endl; }
};
class cat : public animal
{
// members, constructors and other methods...
public:
cat(){}
virtual ~cat(){}
void what_do_you_eat() { cout << "i eat cat food" << endl; }
};
class dog : public animal
{
// members, constructors and other methods...
public:
dog(){}
virtual ~dog(){}
void what_do_you_eat() { cout << "i eat dog food" << endl; }
};
int main() {
std::list<animal*> animals;
animal *a=new animal();
dog *d=new dog();
cat *c = new cat();
animals.push_back( a );
animals.push_back( d );
animals.push_back( c );
for (std::list<animal*>::iterator itr=animals.begin(); itr!=animals.end(); ++itr)
{
(*itr)->what_do_you_eat();
}
return 0;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.