2010-05-15 87 views
1

我试图创建一个结构阵列,其连结输入字符串类别如下:类查找结构阵列++

struct {string command; CommandPath cPath;} cPathLookup[] = { 
    {"set an alarm", AlarmCommandPath}, 
    {"send an email", EmailCommandPath}, 
    {"", NULL} 
}; 

将被使用如下:

CommandPath *cPath = NULL; 
string input; 
getline(cin, input); 
for(int i = 0; cPathLookup[i] != ""; i++) { 
     if(cPathLookup[i].command == input) 
       cPath = new cPathLookup[i].cPath; 
} 

显然,这段代码没有意义,但我认为我的意图很明显 - 根据输入,我想将cPath初始化为新的AlarmCommandPath或新的EmailCommandPath。我可以用一个函数根据输入返回一个实例来处理它,但是整个ifs序列看起来不够好看。

我还应该注意,如果它不明显且重要,那么AlarmCommandPath和EmailCommandPath是从CommandPath派生而来的,而CommandPath是一个抽象类。

感谢您提供任何帮助。

编辑:我只注意到,尽管COMMANDPATH是抽象的,我有一个声明:

CommandPath *cPath = NULL; 

的工作代码。为什么编译?

回答

1

AlarmCommandPath和EmailCommandPath是从COmmandPath派生的,对吗?

在这种情况下,您无法将AlarmCommandPath/EmailCommandPath的实例分配给CommandPath - 这在技术上是可行的,但它不会做到您想要的。实例 CommandPath将保留为CommandPath的一个实例(它将具有CommandPath的虚函数表),而不管分配给它的是什么。

您需要使用工厂方法(将返回CommandPath *的函数)。类似的东西:

struct A{ 
}; 

struct B: public A{ 
}; 

struct C: public A{ 
}; 

A* factoryA(){ 
    return new A(); 
} 

A* factoryB(){ 
    return new B(); 
} 

A* factoryC(){ 
    return new C(); 
} 

typedef A* (*FactoryMethod)(); 

struct{ 
    const char* command; 
    FactoryMethod factoryMethod; 
} factoryTable[] = { 
    {"A", factoryA}, 
    {"B", factoryB}, 
    {"C", factoryC}, 
    {0,0} 
}; 
+0

这可以做到没有堆分配?我的意思是,这些工厂方法可以在堆栈上构造一个A或B或C并按值返回它吗? – Segfault 2014-06-05 14:29:40

1

您不能在结构中存储类型,但可以存储指向创建类型的函数的指针。

CommandPath * CreateEmail() { 
    return new EmailCommandPath; 
} 

CommandPath * CreateAlarm() { 
    return new AlarmCommandPath; 
} 

然后你的结构是这样的:

typedef Command * (* CreateFunc)(); 
struct MyMap { 
    string command; 
    CreateFunc func; 
}; 

和地图:

MyMap m[] = {{"email", CreateEmail }, {"alarm", CreateAlarm}}; 

你再看看像以前那样得到一些索引i,并使用它:

CommandPath * p = m[i].func(): 

你可以创建指针来抽象t ypes - 你不能创建它们的实例。

0

我假设你想如果你的系统\ else语句来实现查表作为替代到大。

为了清楚起见,我会选择使用工厂设计模式。如果在很多地方围绕代码重复执行,那么拥有大量的if/else逻辑将非常糟糕。只要它在一个地方,即工厂,那么在我看来,你有一个很好的设计。

0

就我个人而言,如果您只有1个工厂为其接收的字符串的不同值创建不同的“CommandPaths”,我并不认为这是一个巨大的问题。无论如何,你的代码不会工作,因为你不能按照你的方式存储类型。

如果我必须这样做,那么我会使用函数指针指向工厂函数,并使用std :: map将字符串映射到这些函数(如代码中所示),也许可以将指针包装在适当的智能而不是终场前,使用原始指针:

#include <string> 
#include <map> 

struct A { 
}; 

struct B : public A { 
}; 

struct C : public A { 
}; 

A *BFactory(){ 
    return new B(); 
} 

A *CFactory(){ 
    return new C(); 
} 

typedef A *(*Factory)(); 
typedef std::pair<std::string,Factory> Pair; 
typedef std::map<std::string,Factory> Map; 

Pair Pairs[] = 
{ 
    std::make_pair("alarm", BFactory), 
    std::make_pair("email", CFactory) 
}; 

Map Lookup(Pairs, Pairs + sizeof(Pairs)/sizeof(*Pairs)); 

A *CreateInstance(const std::string &Type) 
{ 
    Map::const_iterator i = Lookup.find(Type); 

    if(i != Lookup.end()) 
     return i->second(); 
    else 
     return 0; 
} 

至于你提到的指针和抽象类的问题,你可以有一个指向一个抽象类,但不能实例化一个抽象类。