我正在尝试创建一个结构数组,它将输入字符串链接到类,如下所示:
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;
在工作代码中。为什么要编译?
答案 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;
}
关于指针和抽象类的问题,你可以有一个指向抽象类的指针,但你不能实例化一个抽象类。