C++创建动态对象

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 的形式)

使功能更加强大

updatedupdated2022-01-192022-01-19