当所有类型未知时从基类重载函数
我偶然发现了一个问题,乍一看很容易解决,但仔细研究后似乎并非如此。
我的程序中有一些需要处理多种类型的项目,因此我决定以通用的、可扩展的方式处理这些项目:
class ItemBase
{
public:
virtual ~ItemBase() = 0 {}
// pure virtual class, some extra members
};
template<typename T>
class ItemT : public ItemBase
{
public:
ItemT(const T &data) : m_Data(data) {}
T m_Data;
};
我现在可以在集合中存储任何类型:
std::vector<ItemBase*> items;
这很好。现在我有 GUI 组件,我想与此类分开,所以我想根据类型生成 GUI 组件:
GuiComponent* BuildComponent(ItemT<int> &item)
{
// do whatever based on this type, the int is needed
}
GuiComponent* BuildComponent(ItemT<double> &item)
{
// do whatever based on this type, the double is needed
}
这几乎是漂亮的编码。不幸的是它不起作用。正如该程序所示:
std::vector<ItemBase*> m_Items;
m_Items.push_back(new ItemT<int>(3));
m_Items.push_back(new ItemT<double>(2.0));
BuildComponent(*m_Items[0]);
因为 m_Items[0] 的类型为 ItemBase*。
那么我该如何解决这个问题呢?什么设计模式或模板技巧可以帮助我解决这个问题?
I've stumbled into a problem which, at a glance, is easy cplusplusable, but on careful study appears not to be.
I have items in my program which I will need to work with many types, so I have decided to handle these in a generic, extensible way:
class ItemBase
{
public:
virtual ~ItemBase() = 0 {}
// pure virtual class, some extra members
};
template<typename T>
class ItemT : public ItemBase
{
public:
ItemT(const T &data) : m_Data(data) {}
T m_Data;
};
I can now store any type in a collection:
std::vector<ItemBase*> items;
This is fine. Now I have GUI components I want to keep separate from this class so I want to generate the GUI components depending on type:
GuiComponent* BuildComponent(ItemT<int> &item)
{
// do whatever based on this type, the int is needed
}
GuiComponent* BuildComponent(ItemT<double> &item)
{
// do whatever based on this type, the double is needed
}
Which is almost beautiful coding. Unfortunately it does not work. As this program shows:
std::vector<ItemBase*> m_Items;
m_Items.push_back(new ItemT<int>(3));
m_Items.push_back(new ItemT<double>(2.0));
BuildComponent(*m_Items[0]);
Because m_Items[0] is of type ItemBase*.
So how do I solve this problem? What design pattern or template trickery can help me out here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
简单的答案是:在
ItemBase
中添加一个虚拟buildComponent
方法。但是,由于您希望将 GUI 组件分开,因此我建议使用 Visitor 模式。一个非常简单的实现包括:
ItemBase
中添加单个accept(AbstractVisitorType &)
虚拟方法visitor.visit 在每个派生类中实现此方法(*this)
,这意味着AbstractVisitorType
必须为可能调用的每个具体类型提供一个虚拟visit
方法(请参阅下面的注释visit
重载中实例化适当的 GUI 对象。但请注意,Visitor 模式仅适用于相当稳定的类层次结构:使用 ItemT 模板的新实例将需要在 Visitor 端进行维护来处理这种新类型(但您最初的想法也有同样的问题)。
现代 C++ 设计(Andrei Alexandrescu)的第 10 章是一本关于访问者模式的好书。
The easy answer would be : add a virtual
buildComponent
method inItemBase
. However, as you want to keep the GUI Components separated, I'd recommend a Visitor pattern.A very simple implementation would consist of :
accept(AbstractVisitorType &)
virtual method inItemBase
visitor.visit(*this)
, which means that theAbstractVisitorType
must provide a virtualvisit
method for every concrete type it might be called with (see note below)visit
overload based on the parameter type.Note however that the Visitor pattern is only appropriate for a reasonably stable class hierarchy : using a new instantiation of the ItemT template will require maintenance on the Visitor side to handle this new type (but your initial idea had the same issue).
Chapter 10 of Modern C++ Design (Andrei Alexandrescu) is a great read regarding the visitor pattern.