C++ 使用字符串在C++;实例化类
正在寻找一种避免大量IF/ELSE的方法,并使用查找表将字符串解析为要实例化的特定类,这些类都派生自基类。 这样的事情可能发生吗?如果可能,怎么可能C++ 使用字符串在C++;实例化类,c++,C++,正在寻找一种避免大量IF/ELSE的方法,并使用查找表将字符串解析为要实例化的特定类,这些类都派生自基类。 这样的事情可能发生吗?如果可能,怎么可能 typedef struct BaseClass { } BaseClass; typedef struct DerivedClassOne : BaseClass { } DerivedClassOne; typedef struct DerivedClassTwo : BaseClass { } DerivedClassTwo; type
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”都需要一个新实例)遇到了我在下面发布的,但该模式很有价值。@约翰卡斯特:我给出的方法在每次遇到该模式时也会创建一个新实例:映射存储函数指针,而不是实例,每次调用函数都会创建一个新实例。感谢您坚持我的观点。我将更新我的模式以使用您的模式,因为它很有用更优雅,在我工作后跟进。