C++ 使用字符串在C++;实例化类

C++ 使用字符串在C++;实例化类,c++,C++,正在寻找一种避免大量IF/ELSE的方法,并使用查找表将字符串解析为要实例化的特定类,这些类都派生自基类。 这样的事情可能发生吗?如果可能,怎么可能 typedef struct BaseClass { } BaseClass; typedef struct DerivedClassOne : BaseClass { } DerivedClassOne; typedef struct DerivedClassTwo : BaseClass { } DerivedClassTwo; type

正在寻找一种避免大量IF/ELSE的方法,并使用查找表将字符串解析为要实例化的特定类,这些类都派生自基类。 这样的事情可能发生吗?如果可能,怎么可能

typedef struct BaseClass
{
} BaseClass;

typedef struct DerivedClassOne : BaseClass
{
} DerivedClassOne;

typedef struct DerivedClassTwo : BaseClass
{
} DerivedClassTwo;

typedef struct
{
    const char *name;
    BaseClass class;
} LookupList;

LookupList list[] = {
    {"ClassOne", DerivedClassOne},
    {"ClassTwo", DerivedClassTwo}
};

BaseClass *InstantiateFromString(char *name)
{
    int i;
    for (i = 0; i < 2; i++)
    {
        if (!strcmp(name, list[i].name))
            return new list[i].class();
    }
}

int main (int argc, char *argv[])
{
    BaseClass *myObjectFromLookup = InstantiateFromString("ClassOne");
}
typedef结构基类
{
}基类;
typedef结构DerivedClassOne:基类
{
}衍生一类;
typedef结构DerivedClass2:基类
{
}第二类;
类型定义结构
{
常量字符*名称;
基类;
}LookupList;
LookupList列表[]={
{“ClassOne”,DerivedClassOne},
{“类二”,派生类二}
};
基类*实例化eFromString(字符*名称)
{
int i;
对于(i=0;i<2;i++)
{
如果(!strcmp(名称,列表[i].name))
返回新列表[i]。类();
}
}
int main(int argc,char*argv[])
{
BaseClass*myObjectFromLookup=InstanceFromString(“ClassOne”);
}

您不能像这样初始化列表

typedef struct
{
    const char *name;
    BaseClass class;
} LookupList;

LookupList list[] = {
    {"ClassOne", DerivedClassOne},
    {"ClassTwo", DerivedClassTwo}
};

class是一个基类对象,而初始化值是DerivedClassOne,它是一个类。这没有道理。您将收到编译器错误。

您应该能够执行以下操作:

template<class C>
BaseClass * makeObject<C> () {
    return new C;
}

struct LookupList {
    const char* name;
    BaseClass * (*factoryFunction) ();
};

LookupList list [] = {
    {"ClassOne", &makeObject<DerivedClassOne>},
    {"ClassTwo", &makeObject<DerivedClassTwo>}
};

...

... instantiateFromString ...
    return list[i].factoryFunction ();
模板
基类*makeObject(){
返回新的C;
}
结构LookupList{
常量字符*名称;
基类*(*工厂函数)();
};
LookupList列表[]={
{ClassOne',&makeObject},
{“ClassTwo”,&makeObject}
};
...
... 实例化eFromString。。。
返回列表[i].factoryFunction();

然而,对于
LookupList
,我更喜欢一个映射而不是一个数组。此外,您可能希望熟悉C++11中的函数语法。

首先,语法入门:

struct Base {
    virtual ~Base() {} // do not forget this if you need polymorphism
};
然后,一个“工厂”功能:

template <typename T>
std::unique_ptr<Base> makeBase() { return std::unique_ptr<Base>(new T{}); }
模板
std::unique_ptr makeBase(){return std::unique_ptr(new T{});}
此功能的类型为:

using BaseMaker = std::unique_ptr<Base>(*)();
使用BaseMaker=std::unique_ptr(*)();
最后,总而言之:

struct DerivedOne: Base {}; struct DerivedTwo: Base {};

using BaseMakerMap = std::map<std::string, BaseMaker>;

BaseMakerMap const map = { { "DerivedOne", makeBase<DerivedOne> },
                           { "DerivedTwo", makeBase<DerivedTwo> } };

std::unique_ptr<Base> makeFromName(std::string const& n) {
    BaseMakerMap::const_iterator it = map.find(n);

    if (it == map.end()) { return std::unique_ptr<Base>(); } // not found

    BaseMaker maker = it->second;

    return maker();
}
struct-DerivedOne:Base{};结构派生二:基{};
使用BaseMakerMap=std::map;
BaseMakerMap常量映射={{“DerivedOne”,makeBase},
{“DerivedTwo”,makeBase};
std::unique_ptr makeFromName(std::string const&n){
BaseMakerMap::const_迭代器it=map.find(n);
如果(it==map.end()){return std::unique_ptr();}//未找到
BaseMaker=it->second;
退货制造商();
}

如果您的编译器与C++11兼容,您可以使用lambdas和
std::map轻松实现这一点

#include <iostream>
#include <string>
#include <map>
#include <functional>

using namespace std;

struct BaseClass {virtual void foo()=0;};
struct DerivedClass1 : public BaseClass {void foo() {cout << "1" << endl;}};
struct DerivedClass2 : public BaseClass {void foo() {cout << "2" << endl;}};

// Here is the core of the solution: this map of lambdas does all the "magic"
map<string,function<BaseClass*()> > factory {
    {"one", [](){return new DerivedClass1();}}
,   {"two", [](){return new DerivedClass2();}}
};

int main() {
    BaseClass *a = factory["one"](); // Note the function call () at the end
    BaseClass *b = factory["two"]();
    a->foo();
    b->foo();
    delete a;
    delete b;
    return 0;
}
#包括
#包括
#包括
#包括
使用名称空间std;
结构基类{virtual void foo()=0;};

CultPrdEdCys1:公共BaseCass{VoeFoE(){cUT,不需要<代码> TyPulf类 C++,你知道,为什么不使用<代码> STD::MAP< /Cord>(当然,<代码>工厂< /C>是一个适当的工厂函数的原型,当然)。重点是,不要使用C样式字符串和线性搜索,使用适当的类。查看工厂模式。谢谢,这是正确的答案,尽管我忘了提到我正在尝试避免STL。听起来所有这些都只是在后台为实例化特定的对象类型。也许我可以在数组中有一个函数指针,每个指针指向一个单独的静态函数。@user1054922正确-使用标准库是偶然的,我把它放在那里是为了缩短查找时间。你完全可以用一对数组替换它,就像你在文章中所做的那样。这看起来是一个很有前途的pattern,但它有一些编译错误,不仅仅是修复
makeFromName()中的
map
引用的问题
错误C2207:'std::pair::second':类模板的成员无法获取函数类型
错误C3867:'std::pair::second':函数调用缺少参数列表;使用“&std::pair::second”创建指向成员的指针
错误C2064:术语不会对包含0个参数的函数求值
@johncaster:我修复了函数指针声明和
maker
的类型,现在可以为我编译了。感谢更新!我需要一些稍微不同的东西(每次“name”都需要一个新实例)遇到了我在下面发布的,但该模式很有价值。@约翰卡斯特:我给出的方法在每次遇到该模式时也会创建一个新实例:映射存储函数指针,而不是实例,每次调用函数都会创建一个新实例。感谢您坚持我的观点。我将更新我的模式以使用您的模式,因为它很有用更优雅,在我工作后跟进。