首页 > 解决方案 > 根据 C++ 中的字符串值创建类对象实例的好方法?

问题描述

请参阅问题的代码片段:

class Base; 
typedef Base* BasePtr; 

template<typename D>
BasePtr CreateDerivedClass() {
    return new D();
}

class D1 : public Base {
....
};

class D2 : public Base {
....
}

void main() {
    std::string derived_name = {"D1", "D2"}; 
    std::vector<BasePtr> derived_vec; 
    for (auto& name : derived_name) {
// QUESTION: Other than factory design pattern, how can I pass the derived 
// class typename which is the value of string "name" to CreateDerivedClass<name> ?
        derived_vec.push_back(CreateDerivedClass<name>()); 
    }
}

注意:在这里,我不想使用在定义期间需要派生类寄存器本身的工厂设计模式。

标签: c++factory-pattern

解决方案


模板参数值必须在编译时已知。没有简单的方法可以在运行时直接将字符串转换为用于模板参数的类型。您必须在运行时比较字符串值来决定调用哪个特化。CreateDerivedClass

例如,处理此问题的最简单方法是使用 astd::map其中的元素保存指向您希望能够调用的专用函数的指针,例如:

using createFuncType = BasePtr (*)();
std::map<std::string, createFuncType> createFuncs;
createFuncs["D1"] = &CreateDerivedClass<D1>;
createFuncs["D2"] = &CreateDerivedClass<D2>;
...

然后你可以这样做:

std::string derived_names[] = {"D1", "D2"}; 
std::vector<BasePtr> derived_vec; 
for (auto& name : derived_names) {
    derived_vec.push_back(createFuncs[name]());
}

在这种情况下确实没有其他选择。


话虽如此,您应该使用std::unique_ptr<Base>而不是原始Base*指针,例如:

#include <map>
#include <vector>
#include <string>
#include <memory>

class Base {
public:
    virtual ~Base() = default;
};

using BasePtr = std::unique_ptr<Base>;
using createFuncType = BasePtr (*)();

template<typename D>
BasePtr CreateDerivedClass() {
    return std::make_unique<D>();
}

class D1 : public Base {
    ...
};

class D2 : public Base {
    ...
}

...

int main() {
    std::map<std::string, createFuncType> createFuncs;
    createFuncs["D1"] = &CreateDerivedClass<D1>;
    createFuncs["D2"] = &CreateDerivedClass<D2>;
    ...

    std::string derived_names = {"D1", "D2", ...};
    std::vector<BasePtr> derived_vec; 
    for (auto& name : derived_names) {
        derived_vec.push_back(createFuncs[name]()); 
    }

    ...

    return 0;
}

推荐阅读