C++ 当所有类型都未知时,从基类重载函数
我偶然遇到了一个问题,乍一看,这个问题很容易解决,但经过仔细研究,似乎不太可能 我的程序中有需要处理多种类型的项目,因此我决定以通用的、可扩展的方式处理这些项目:C++ 当所有类型都未知时,从基类重载函数,c++,templates,inheritance,overloading,C++,Templates,Inheritance,Overloading,我偶然遇到了一个问题,乍一看,这个问题很容易解决,但经过仔细研究,似乎不太可能 我的程序中有需要处理多种类型的项目,因此我决定以通用的、可扩展的方式处理这些项目: class ItemBase { public: virtual ~ItemBase() = 0 {} // pure virtual class, some extra members }; template<typename T> class ItemT : public ItemBase { public
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;
};
class项目库
{
公众:
virtual~ItemBase()=0{}
//纯虚拟类,一些额外的成员
};
样板
类ItemT:公共项目库
{
公众:
ItemT(const T&data):m_data(data){}
T m_数据;
};
我现在可以在集合中存储任何类型:
std::vector<ItemBase*> items;
std::向量项;
这很好。现在我有了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
}
GuiComponent*BuildComponent(ItemT&item)
{
//基于此类型执行任何操作,都需要int
}
GuiComponent*BuildComponent(ItemT&item)
{
//根据这种类型做任何事情,都需要双精度
}
这几乎是美丽的编码。不幸的是,它不起作用。如本节目所示:
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]);
std::向量m_项;
m_项。推回(新项T(3));
m_项。推回(新项T(2.0));
BuildComponent(*m_项[0]);
因为m_Items[0]的类型为ItemBase*
那么我该如何解决这个问题呢?什么样的设计模式或模板技巧可以帮助我解决这个问题?简单的答案是:在
itembease
中添加一个虚拟的buildComponent
方法。但是,由于您希望将GUI组件分开,我建议使用一种模式
一个非常简单的实现将包括:
- 在
ItemBase
- 通过调用
,在每个派生类中实现此方法,这意味着visitor.visit(*this)
必须为可能调用它的每个具体类型提供一个虚拟的AbstractVisitorType
方法(参见下面的注释)visit
- 提供此访问者的具体实现,它将根据参数类型在每个
重载中实例化相应的GUI对象visit
《现代C++设计》第10章(Andrei Alexandrescu)是一个关于访问者模式的伟大读物。 < P>容易回答的是:在
- 在
ItemBase
- 通过调用
,在每个派生类中实现此方法,这意味着visitor.visit(*this)
必须为可能调用它的每个具体类型提供一个虚拟的AbstractVisitorType
方法(参见下面的注释)visit
- 提供此访问者的具体实现,它将根据参数类型在每个
重载中实例化相应的GUI对象visit
《现代C++设计》第10章(Andrei Alexandrescu)是一个关于访问者模式的伟大读物。你是否会遇到编译时错误?运行时错误?编译时“任何重载都不能转换所有参数类型”。首先,您的抽象声明是不正确的。抽象声明后面不应该有{}。{}用于派生类实现。这也意味着您的ItemT类需要为基类实现析构函数。它被称为带主体的纯虚拟类:非常罕见,但完全合法。您是否遇到编译时错误?运行时错误?编译时“任何重载都不能转换所有参数类型”。首先,您的抽象声明是不正确的。抽象声明后面不应该有{}。{}用于派生类实现。这也意味着您的ItemT类需要为基类实现析构函数。它被称为带主体的纯虚拟:非常罕见,但完全合法。是的,我知道我需要并行维护两个类继承人。你有不同的想法吗?访客模式几乎完美无瑕。不幸的是,我必须让这个类知道如何使用它,包括头文件和所有这些可重写的函数。很遗憾,无法对虚拟函数进行模板化。结构访问者{template void visit(const ItemT&t){t item=t.m_Data;};};很高兴:)你可能想用谷歌搜索非循环访问者,让其走得更远一点(尽管这对你的需求来说有点过分了)是的,我知道我需要同时维护两个类继承人。你有不同的想法吗?访客模式几乎完美无瑕。不幸的是,我必须让这个类知道如何使用它,包括头文件和所有这些可重写的函数。很遗憾,无法对虚拟函数进行模板化。结构访问者{template void visit(const ItemT&t){t item=t.m_Data;};};很高兴:)你可能想用谷歌搜索非循环访问者,让他们走得更远一点(尽管这对你的需求来说有点过分了)