【问题标题】:How to get an object of a unknown class with given classname如何获取具有给定类名的未知类的对象
【发布时间】:2010-01-15 22:13:59
【问题描述】:

我正在寻找一种方法来确定在运行时应分配哪种类型的对象(基于给定的类名,其类型为 const char*)。

当然,最简单的方法是使用 ifs /else ifs 的负载,但这似乎不适用,因为我有超过 100 个不同的类(至少它们都派生自一个基类),而且我还必须定期添加新课程。

我已经提出了初稿,但遗憾的是它还没有编译(mingw & g++ 4.4)

template<typename TBase, typename TDerived, typename... TArgs>
Base* get_classobject(const char* classname)
{
    if(strcmp(classname,typeid(TDerived).name())==0)
        return new TDerived; //
    else if(sizeof...(TArgs)>0)
        return get_classobject<TBase,TArgs...>(classname);
    else
        return 0;
}


int main()
{
    Base* obj = get_classobject<Base,A,Foo,B,C>("Foo");
    // ^- Types A B C and Foo are all derived from Base
    delete obj; //of course we got an virtual dtor ;)
    return 0;
}

但是 sizeof...(TArgs)&gt;0 并不能阻止 gcc 尝试为失败的 get_classobject&lt;TBase,const char*&gt;(const char*) 生成代码

你有什么想法,如何解决这个问题,或任何其他想法? 谢谢。

编辑:我解决了:

template<typename TBase, typename TDerived>
Base* get_classobject(const char* classname)
{
    if(strcmp(classname,typeid(TDerived).name())==0)
        return new TDerived;
    return 0;
}

template<typename TBase, typename TDerived, typename TArg, typename... TArgs>
Base* get_classobject(const char* classname)
{
    if(strcmp(classname,typeid(TDerived).name())==0)
        return new TDerived;
    return get_classobject<TBase,TArg,TArgs...>(classname);
}

编辑感兴趣的读者:
您现在应该知道上面的实现根本不是独立于编译器的。 typeif(sometype).name() 的输出是特定于编译器/实现的。 在所有派生类中使用static const char* name 变量或函数可以解决此问题,但会增加大量工作(当然您可以为此使用宏,但如果您已经在使用宏,您也可以使用另一个对象工厂方法)

【问题讨论】:

  • 闻起来像你需要实现一个工厂和clone 方法。使用clone()接口,你可以创建一个家族的对象,而不需要知道它们的类名。
  • 我不想显得挑剔,但真的......这闻起来很糟糕。首先,typeid 的使用颇具争议,但我还想指出这种方法的效率低下 > 您执行具有线性复杂性的搜索,并且您必须实际精确所有可能生成的类型。 ..我什至不想考虑噩梦般的维护成本。
  • typeid 可以很容易地用静态 ::name 函数替换,线性搜索不是问题,因为我只调用过一次此方法(除了我查看的任何其他对象工厂也有线性搜索或滥用宏)

标签: c++ c++11 function-templates


【解决方案1】:

你不能直接声明

template<typename TBase, typename TDerived, typename TArg, typename... TArgs>

?

那你就可以专攻这种情况了

typename TBase, typename TDerived, typename TArg

【讨论】:

  • 如果我这样做,它会不会提前一个递归步骤失败?
  • 您正在尝试获取 1+ 模板参数,而不是 0+ 对吗?您可以将模板专门用于 0 案例。
【解决方案2】:

阅读here 上的答案,您可能需要一个工厂。

【讨论】:

    【解决方案3】:

    制作一个没有可变参数模板的专用 get_classobject() 怎么样?这将停止递归。

    然后,您将拥有一个带有可变参数模板的定义,而另一个只有 template&lt;typename TBase, typename TDerived&gt; 的定义。另一个想法是创建一个仅接受 const char* 并返回 0 的非模板重载。

    【讨论】:

    • 已经试过了,还是得到error: no matching function for call to 'get_classobject(const char*&amp;)'|
    【解决方案4】:

    这听起来像是在寻找经典的对象工厂模式。看看这个stackoverflow question。我个人喜欢这个method

    【讨论】:

    • 使用该模式时,您必须自己编写代码,使用编译器为我生成的方式;)
    • @smerlin 如果我理解 您的 方式,您将需要在每次需要调用 get_classobject() 时链接/编写所有派生类。因此,当添加或删除一个类时,这是一个管理/手动过程。我描述的方式更自动。基本上你只需要添加两行。类声明中的 METADECL 和编译单元(.cpp 文件)中的 METAIMPL,最好靠近构造函数。该解决方案的这一自动化功能真正吸引了我,然后甚至可以通过加载共享对象(.so/.dll 文件)在运行时添加类完成...
    • 无论如何我只需要调用一次这个函数,如果我不得不多次调用它们,我会添加一个(内联)包装函数,这样我只需要编写一次类
    猜你喜欢
    • 2011-01-22
    • 2021-11-12
    • 2013-09-25
    • 2011-08-24
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 2012-03-15
    相关资源
    最近更新 更多