我有这样的课程: 1类 等级2 CLASS3 CLASS4 Class5 Class6的 ... ... ... ClassN
在其中一个函数中,我需要根据函数的输入参数创建类的对象。
例如,如果输入为1,那么我需要为Class1创建一个对象,如果是2则为Class2对象。
是否可以在不使用if条件的情况下创建对象?我不想要所有课程的条件。
答案 0 :(得分:3)
由于您使用继承,因此需要一个工厂函数来生成任何派生类型...
template<typename T>
base * spawn ()
{
return new T();
}
...以及支持operator[]
随机访问的容器。
如果您需要不连续的索引,请选择地图:
std::map<int, base *(*)()> map_spawner =
{
{ 0, &spawn<child_1> },
{ 1, &spawn<child_2> }
};
如果索引是连续的,请选择一个向量:
std::vector<base *(*)()> vec_spawner =
{
&spawn<child_1>,
&spawn<child_2>
};
工作示例:
#include <map>
#include <vector>
class base
{
public:
virtual ~base () = default;
public:
virtual int f () const = 0;
};
class child_1 : public base
{
public:
int f () const override { return 1; }
};
class child_2 : public base
{
public:
int f () const override { return 2; }
};
template<typename T>
base * spawn ()
{
return new T();
}
int main ()
{
// With a vector
std::vector<base *(*)()> vec_spawner =
{
&spawn<child_1>,
&spawn<child_2>
};
base * child = vec_spawner[0]();
// Do something with child here ...
delete child;
// With a map
std::map<int, base *(*)()> map_spawner =
{
{ 0, &spawn<child_1> },
{ 1, &spawn<child_2> }
};
child = map_spawner[1]();
// Do something with child here ...
delete child;
}
现在您可以使用用户输入来生成特定实例。
如果你派生的类型构造函数没有共享相同的参数,不幸的是我不知道你不能使用任何容器......我能想到的唯一可能性就是这个(工作示例):< / p>
#include <utility>
class base
{
public:
virtual ~base () = default;
public:
virtual int f () const = 0;
};
class child_1 : public base
{
public:
int f () const override { return 1; }
};
class child_2 : public base
{
public:
child_2 (int i) { (void) i; }
public:
int f () const override { return 2; }
};
template<typename... Args>
base * spawn (int input, Args && ... args)
{
switch (input)
{
case 0: return new child_1 {};
case 1: return new child_2 { std::forward<Args>(args)... };
// ...
}
return nullptr;
}
int main ()
{
int input = 1;
base * child = spawn(input, 42);
// Do something with child here ...
delete child;
}
答案 1 :(得分:0)
如果你的项目是windows dll,我有一个可能的解决方案:
在项目中为每个派生类定义工厂方法。
创建Class1
对象的工厂方法应该命名为us1
(或者是用户输入以触发此对象创建)。
然后使用GetProcAddress
API根据其名称获取工厂方法的地址(同样名称是用户输入) - 获取后,只需调用它来创建对象。
显示概念的一些代码段(由于您尚未发布代码,因此很难建议真实的内容)
class Base
{
public:
void foo() = 0;
}
class Derived1 : public Base
{
public:
void foo() {};
}
class Derived2 : public Base
{
public:
void foo() {};
}
extern "C"
{
void __declspec(dllexport) us1 (Base*& pObj)
{
pObj = new Derived1();
}
void __declspec(dllexport) us2 (Base*& pObj)
{
pObj = new Derived2();
}
}
然后在您的cpp文件上使用类似
的内容typedef void (__cdecl FUNCPROC)(Base*&);
string userInput;
cin >> userInput;
// get a handle to your dll memory (if this is a dll)
// assuming moduleHandle points to your dll memory
FUNCPROC* pProcAddr = GetProcAddress((HMODULE)moduleHandle, userInput);
现在pProcAddr
是一个指向基于用户输入的受尊重工厂方法的指针。
获得正确的对象
Base* pTmp = NULL;
pProcAddr(pTmp);
现在我的上述提议尚未完成,还有更多事情需要处理(检查有效的用户输入,检查内存中存在的工厂方法等等),但它应该给你一个大致的想法。
答案 2 :(得分:0)
我在很多情况下使用此代码,例如你的。
假设您的所有课程Class1
〜ClassN
都来自一个抽象基类class Base
。
#include <vector>
#include <memory>
#include <functional>
std::vector<std::function<std::shared_ptr<Base> ()>> CtorList = {
[] { return std::shared_ptr<Base>(new Class1); },
[] { return std::shared_ptr<Base>(new Class2); },
[] { return std::shared_ptr<Base>(new ClassN); },
};
// Create
std::shared_ptr<Base> p = CtorList[num - 1]();
答案 3 :(得分:0)
我建议使用从输入类型映射到工厂对象的地图。工厂对象具有返回所需类型的虚方法。因此,每个类(Class1 ... ClassN)都有一个匹配的工厂类(FCi),它知道如何构造(Classi)的对象。
typedef std::map< Input, Factory > FactoryMap;
FactoryMap factoryMap;
void initFactoryMap()
{
factoryMap[ Input1 ] = new FactoryForClass1(); // subclass of Factory, implementing constructClass
factoryMap[ Input2 ] = new FactoryForClass2();
factoryMap[ Input3 ] = new FactoryForClass3();
...
}
AbstractClass *inputHandler( Input n )
{
return factoryMap[n]->constructClass( n ); // may not need to pass n in
}
答案 4 :(得分:0)
我真的很感激你已经定义了这么多类的努力...但是我宁愿定义一个带有一个函数的类,它将负责创建所需的表我将试图找出一些逻辑方式如果表格类似,则创建/打印表格...或者在最坏的情况下,我会使用switch
语句来选择要创建/打印的表格。