访问std :: list中派生类的属性

时间:2013-09-18 17:22:28

标签: c++ list iterator

我想要做的是我有一个列表std::list<Displayable> display_queue

可显示在Displayable.h中定义为:

class Displayable { 

    public:

        int x, y;

        Displayable() : x(0), y(0) {}
        Displayable(int x, int y) : x(x), y(y) {}

};

DifferentDisplayable as:

class DifferentDisplayable : public Displayable { 

    public:

        std::string id;

        DifferentDisplayable() : Displayable(), id("") {}
        DifferentDisplayable(int x, int y) : Displayable(x, y), id("") {}
        DifferentDisplayable(int x, int y, std::string id) : Displayable(x, y), id(id) {} 

};

添加到列表中的项目是:

Displayable disp_one;
DifferentDisplayable disp_two(10, 10, "the id");

display_queue.push_back(disp);
display_queue.push_back(disp_two);

由于DifferentDisplayable来自Displayable,因此可以将其存储在列表中,但我无法弄清楚的是我怎样才能在std::string id中访问DifferentDisplayable {1}}迭代遍历列表(display_queue),如下所示:

for (std::list<Displayable>::iterator i = display_queue.begin(); i != display_queue.end(); i++) {

    // insert code here

}

提前感谢您的回答

2 个答案:

答案 0 :(得分:2)

std::list<Displayable> display_queue;

该列表只能保存Displayable个对象,但不能保存任何派生的子对象。当您尝试执行display_queue.push_back(disp_two);时,对象被切片,并且只有基类子对象存储在列表中。

答案 1 :(得分:1)

如果所有派生类都不需要'id',那么不要直接从循环中尝试访问它,而是添加一个使用它的基类方法。例如:

class Displayable
{
public:
  virtual void Display();
  ...
};

(更好的做法是将'class Displayable'作为一个抽象基类,将Display()作为纯虚函数。请参阅下面的链接。)

然后实现可以独立变化:

void Displayable::Display()
{
  // Do something here with 'x' and 'y'
}

void DifferentDisplayable::Display()
{
  // Do something here with 'x', 'y', and 'id'
}

然后在堆上分配对象以避免切片问题:

Displayable* disp_one = new Displayable();
DifferentDisplayable* disp_two = new DifferentDisplayable(10, 10, "the id");

display_queue.push_back(disp);
display_queue.push_back(disp_two);

然后你的循环变为:

for (std::list<Displayable>::iterator i = display_queue.begin(); i != display_queue.end(); ++i) {
  (*i)->Display();
}

记得在完成指示后“删除”指针。

Open-Closed Principle中的Effective C++ 3rd Edition by Scott Meyers和第34项“区分接口的继承和实现的继承”中讨论了这种策略。