c++ 创建动态对象
C++没有反射,但在apolloAUTO中出现了很多读取配置文件然后实例化对象的情况,因此探究了一下用C++动态创建对象,这对理解Java的getInstanceByName也有好处
1.思想
三层结构:
- Class: 实现具体功能(实现类)
- ClassRegister: 实现NewInstance接口(注册类)
- Factory: 实现getInstanceByName,通过map结构,实现一对多(工厂类)
每个Class对应一个ClassRegister,一个Factory对应了多个ClassRegister.
1. 调用Factory.getInstanceByName("ClassA")
2. 查找map,Factory返回ClassARegister
3. 调用ClassARegister的NewInstance接口,返回具体的A对象的指针
2.实现
//Shape.h
// 具体的功能实现类
#ifndef _SHAPE_H_
#define _SHAPE_H_
class Shape
{
public:
virtual void Draw() = 0;
virtual ~Shape() {}
};
class Circle : public Shape
{
public:
void Draw();
~Circle(){};
};
class Square : public Shape
{
public:
void Draw();
~Square(){};
};
class Rectangle : public Shape
{
public:
void Draw();
~Rectangle(){};
};
#endif // _SHAPE_H_
//Shape.cpp
#include "Shape.h"
#include "DynBase.h"
#include <iostream>
void Circle::Draw()
{
std::cout << "Circle" << std::endl;
}
void Square::Draw()
{
std::cout << "Square" << std::endl;
}
void Rectangle::Draw()
{
std::cout << "Rectangle" << endl;
}
// 这里使用了DynBase.h中的宏,注册具体的实现类
REGISTER_CLASS(Circle);
REGISTER_CLASS(Square);
REGISTER_CLASS(Rectangle);
//DynBase.h
#ifndef _DYN_BASE_H_
#define _DYN_BASE_H_
#include <map>
#include <string>
using namespace std;
// 函数指针
typedef void *(*CREATE_FUNC)();
class DynObjectFactory
{
public:
// 通过map寻找对应的注册类
static void *CreateObject(const string &name)
{
map<string, CREATE_FUNC>::const_iterator it;
it = mapCls_.find(name);
if (it == mapCls_.end())
return 0;
else
return it->second(); //func();
}
//在工厂类中注册[注册类]
static void Register(const string &name, CREATE_FUNC func)
{
mapCls_[name] = func;
}
private:
static map<string, CREATE_FUNC> mapCls_;
};
class Register
{
public:
// 一个trick,初始化Register类,实际上是对工厂类注册[注册类]
Register(const string &name, CREATE_FUNC func)
{
DynObjectFactory::Register(name, func);
}
};
// 每次执行一次宏,都会生成一个[注册类],如CircleRegister
// 同时初始化这个类的静态成员reg_,初始的时候调用了动态工厂的Register方法,完成[注册类]自己的注册
#define REGISTER_CLASS(class_name) \
class class_name##Register { \
public: \
static void* NewInstance() \
{ \
return new class_name; \
} \
private: \
static Register reg_; \
}; \
Register class_name##Register::reg_(#class_name, class_name##Register::NewInstance)
#endif // _DYN_BASE_H_
//DynBase.cpp
#include "DynBase.h"
map<string, CREATE_FUNC> DynObjectFactory::mapCls_;
//main.cpp
#include "Shape.h"
#include "DynBase.h"
int main(void)
{
Shape *ps;
ps = static_cast<Shape *>(DynObjectFactory::CreateObject("Circle"));
ps->Draw();
delete ps;
ps = static_cast<Shape *>(DynObjectFactory::CreateObject("Square"));
ps->Draw();
delete ps;
ps = static_cast<Shape *>(DynObjectFactory::CreateObject("Rectangle"));
ps->Draw();
delete ps;
return 0;
}
#CMakeLists.txt
add_executable(demo DynTest.cpp DynBase.h DynBase.cpp Shape.h Shape.cpp)
3.小结
其实从本质上可以自己定义每种Shape对应的Register类,这里使用宏很巧妙地节省了代码,另外,借助每个注册类的静态成员的初始化工厂类,非常巧妙
将类名和创建的函数保存成一个map,然后创建对象时根据类型匹配创建函数即可
4.进阶
利用泛型 支持自定义的结构体(非模板),类(非模板)、枚举、联合 解析类型名称(转换为 A::B::C 的形式)
使功能更加强大