使用索引创建类的对象

时间:2014-07-30 12:25:00

标签: c++ oop

我有这样的课程: 1类 等级2 CLASS3 CLASS4 Class5 Class6的 ... ... ... ClassN

在其中一个函数中,我需要根据函数的输入参数创建类的对象。

例如,如果输入为1,那么我需要为Class1创建一个对象,如果是2则为Class2对象。

是否可以在不使用if条件的情况下创建对象?我不想要所有课程的条件。

5 个答案:

答案 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)

我在很多情况下使用此代码,例如你的。

假设您的所有课程Class1ClassN都来自一个抽象基类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]();

(live example)

答案 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语句来选择要创建/打印的表格。