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

Accessing attributes of a derived class in a std::list

本文关键字:派生 属性 std list 访问      更新时间:2023-10-16

我想做的是我有一个列表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为:

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因此它能够存储在列表中,但我无法弄清楚的是,在迭代列表(display_queue)时,我如何或甚至可以DifferentDisplayable访问std::string id,如下所示:

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

提前感谢您的任何答案

std::list<Displayable> display_queue;

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

如果不是所有派生类都需要"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();
}

记住在完成指针后"删除"指针。

Scott Meyers 在 Effective C++ 3rd Edition 的开放-封闭原则和第 34 项"区分接口继承和实现继承"中讨论了此策略。