假设我有一组以下类:
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; }
}
我想创建一个列表(任何容器都没问题,但我们为这个例子选择std::list<>
):
std::list<animal> animals
animals.push_back( dog() );
animals.push_back( cat() );
但是当我尝试迭代列表时,我得到了这个输出:
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
// ...
然后我尝试制作一个指针列表(std::list<animal *> animals
),输出正确,但此解决方案存在许多问题:
std::list<animal * const> animals
列表而animals
保存的指针可以在我的程序中的任何地方被覆盖。 问题:
是否有可能通过对基类的引用将派生类传递给stl容器,并仍然得到正确的输出?
是否有任何解决方法可以在没有指针的情况下正确执行此操作?目前,我正在编写一个严重依赖于类继承的项目,我现在被困住了,因为我需要创建一个不同类型的对象列表(所有这些类型都直接或间接地从一个基类继承)这似乎是不可能的。
涉及boost
库的解决方案是可以接受的。
答案 0 :(得分:4)
当您处理多态时,容器必须使用任何类型的指针。
最好使用智能指针,在您的情况下std::unique_ptr
将完美地完成工作。
例如:
std::list<std::unieque_ptr<animal>> animals;
animals.emplace_back(new dog {});
animals.emplace_back(new cat {});
注意基类animal
必须有一个虚拟析构函数!
最好将其定义为抽象类:
class animal
{
// NO members, NO constructors only pure virtual methods
public:
virtual animal() {};
virtual void what_do_you_eat() = 0;
};
答案 1 :(得分:-1)
在您的代码中,list<animal>
应为list<animal*>
,然后您必须相应地更改代码的其他行。
请参阅下面的代码。它按预期工作。
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;
}