C ++中的类查找结构数组

时间:2010-05-15 08:30:06

标签: c++ class inheritance pointers

我正在尝试创建一个结构数组,它将输入字符串链接到类,如下所示:

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;

在工作代码中。为什么要编译?

4 个答案:

答案 0 :(得分: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():

您可以创建指向抽象类型的指针 - 您无法创建它们的实例。

答案 1 :(得分: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}
};

答案 2 :(得分:0)

我假设您正在尝试将表查找实现为系统中大型if \ else语句的替代。

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

答案 3 :(得分:0)

就个人而言,如果您只有一个工厂为其收到的字符串的不同值创建不同的“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;
}

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