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
    方法(参见下面的注释)
  • 提供此访问者的具体实现,它将根据参数类型在每个
    visit
    重载中实例化相应的GUI对象
但是请注意,访问者模式仅适用于相当稳定的类层次结构:使用ItemT模板的新实例化将需要访问者端的维护来处理这种新类型(但您最初的想法也有相同的问题)


《现代C++设计》第10章(Andrei Alexandrescu)是一个关于访问者模式的伟大读物。

< P>容易回答的是:在 ItMase< /C>中添加一个虚拟的代码> Bug组件/Cuff>方法。但是,由于您希望将GUI组件分开,我建议使用一种模式

一个非常简单的实现将包括:

  • ItemBase
  • 通过调用
    visitor.visit(*this)
    ,在每个派生类中实现此方法,这意味着
    AbstractVisitorType
    必须为可能调用它的每个具体类型提供一个虚拟的
    visit
    方法(参见下面的注释)
  • 提供此访问者的具体实现,它将根据参数类型在每个
    visit
    重载中实例化相应的GUI对象
但是请注意,访问者模式仅适用于相当稳定的类层次结构:使用ItemT模板的新实例化将需要访问者端的维护来处理这种新类型(但您最初的想法也有相同的问题)


《现代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;};};很高兴:)你可能想用谷歌搜索非循环访问者,让他们走得更远一点(尽管这对你的需求来说有点过分了)