C++由字符串创建对象

思路

先定义基类,然后把子类的创建函数用字典保存起来,用的时候直接调用子类的创建函数即可实现从字符串创建对象实例。

首先是通用的基类

Object.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Object.h
class Object {
protected:
using String = std::string_view;
using Creater = std::function<std::shared_ptr<Object>()>;
using Container = std::unordered_map<String, Creater>;

public:
virtual void Init() = 0; // 一个功能函数示例

static std::shared_ptr<Object> Create(const String& type) {
auto pos = _objs.find(type);
if (pos == _objs.end()) {
std::cout << "String \"" << type << "\" has not registered, you may need to use \"IMPL_OBJECT_CREATION(" << type << ")\" in .cpp file\n";
return nullptr;
}
return _objs[type]();
}

protected:
static void _regist(const String& type, const Creater& creater) {
if (_objs.count(type)) {
std::cout << "Multiple registration of type: " << type << std::endl;
}
_objs[type] = creater;
}

private:
static Container _objs;
};

Object.cpp

1
2
// Object.cpp
Object::Container Object::_objs;

之后有两种做法

第一种

完全使用宏

Object.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Object.h
#define DECL_OBJECT_CREATION(ObjType) \
public: \
static constexpr String GetType() { \
return #ObjType; \
} \
protected: \
static std::shared_ptr<Object> _create() { \
return std::static_pointer_cast<Object>( \
std::make_shared<ObjType>() \
); \
} \
private: \
struct Register { \
Register() { \
Object::_regist(GetType(), &_create); \
} \
}; \
static const Register _register;

#define IMPL_OBJECT_CREATION(ObjType) \
const ObjType::Register ObjType::_register;

子类就要这么写

Object1.h

1
2
3
4
5
6
7
8
// Object1.h
class Object1 : public Object { // 继承
DECL_OBJECT_CREATION(Object1) // 声明宏
public:
void Init() override {
std::cout << "Object1 Init\n";
}
};

Object1.cpp

1
2
// Object1.cpp
IMPL_OBJECT_CREATION(Object1) // 定义宏

第二种

使用一个模板类作为中间层

Object.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Object.h
template<typename T>
class TObject : public Object {
private:
static std::shared_ptr<Object> _create() {
return std::static_pointer_cast<Object>(
std::make_shared<T>()
);
}
virtual const String GetType() = 0;
struct Register {
Register() {
Object::_regist(T().GetType(), &T::_create);
}
};
static const Register _register;
};

#define IMPL_OBJECT_CREATION(ObjType) \
const TObject<ObjType>::Register TObject<ObjType>::_register;

子类要这样写

Object2.h

1
2
3
4
5
6
7
8
9
10
11
// Object2.h
class Object2 : public TObject<Object2> { // 继承
public:
void Init() override {
std::cout << "Object2 Init\n";
}

const String GetType() override { // 实现虚函数
return "Object2";
}
};

Object2.cpp

1
2
// Object2.cpp
IMPL_OBJECT_CREATION(Object2) // 定义宏

使用

1
2
3
4
5
6
7
if (auto o = Object::Create("Object1")) {
o->Init(); // 输出"Object1 Init"
}

if (auto o = Object::Create("Object2")) {
o->Init(); // 输出"Object2 Init"
}