我想要做的是我有一个列表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
}
提前感谢您的回答
答案 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项“区分接口的继承和实现的继承”中讨论了这种策略。