如何从一组派生类创建列表?

时间:2017-07-27 16:48:29

标签: c++ inheritance std

假设我有一组以下类:

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),输出正确,但此解决方案存在许多问题:

  • 因为标准说stl容器不能保存const类型我不能使用std::list<animal * const> animals列表而animals保存的指针可以在我的程序中的任何地方被覆盖。
  • 我需要手动释放它们。

问题:
是否有可能通过对基类的引用将派生类传递给stl容器,并仍然得到正确的输出?

是否有任何解决方法可以在没有指针的情况下正确执行此操作?目前,我正在编写一个严重依赖于类继承的项目,我现在被困住了,因为我需要创建一个不同类型的对象列表(所有这些类型都直接或间接地从一个基类继承)这似乎是不可能的。

涉及boost库的解决方案是可以接受的。

2 个答案:

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