Realize dynamic selection of execution objects by configuring class names through C++ reflection

1. The effect achieved

There are three different classes A, B, and C in the project. Select the class to execute through the configuration file. For example, configure CLASSNAME=A in the configuration file. When we get the CLASSNAME in the configuration, we can perform the method in class A.

2. Realize

2.1 Base class (base class that operates through polymorphism)

//F.h文件内容
#ifndef F_H
#define F_H
class F
{
    
    
    public:
    virtual void fun()=0;
};
#endif

2.2 Object mapping basic class (base class can also be used)

The following can be kept in a header file class.h

//基础类,可以使用基本类F代替
class ClassMappingObject
{
    
    
    public:
    virtual ~ClassMappingObject()=default;
    virtual void classinit()=0;  //为第二种宏定义提供初始化函数,可以没有
};

Type definition using functors

using RegisterFunc = std::function<std::unique_ptr<ClassMappingObject>()>;
inline std::map<std::string ,RegisterFunc> objectMap; //此为全局类的映射表;结构为{类名:类对象}
//在多个项目中可能会出现重复定义等错误,使用inline进行避免

function for registration

static void registerObject(const std::string& name,RegisterFunc func) {
    
     //传入的进行类名和对象
    objectMap[name] = func;
}

Get object by class name

template <typename T>
T* createObject(const std::string& name) {
    
    
    if (objectMap.find(name) == objectMap.end()) {
    
    
        return nullptr;
    }
    auto ptr = objectMap[name]();
    // 从基类动态转换为外部需要的类型
    return dynamic_cast<T*>(ptr.release());
}

Define macros for registration(1)

template <typename T1>
std::unique_ptr<ClassMappingObject> class_make_unique() {
    
    
    auto* ptr = new T1;
    return std::unique_ptr<ClassMappingObject>(dynamic_cast<ClassMappingObject*>(ptr));
}
#ifndef REGISTER_CLASS
#define REGISTER_CLASS(Type)\
static struct _ObjectRegisterTask##Type {
      
       \
    _ObjectRegisterTask##Type() {
      
       \
        registerObject(#Type,class_make_unique<Type>); \
    }; \
} _task##Type; // NOLINT
#endif

Define macros for registration(2)

//第二种宏定义
struct RegisterTask {
    
    
    RegisterTask( string a) {
    
    
        std::cout<<a<<std::endl;
    }
    static string registerfun(const std::string& name,
        std::function<std::unique_ptr<ClassMappingObject>()> func) {
    
    
        registerObject(name,func);
        return name;
    }
};

#ifndef RegisterTask
#define RegisterTask(Type)\
static RegisterTask  task##Type(RegisterTask::registerfun(#Type,class_make_unique<Type>));
#endif

The entire code of class.h

#ifndef CLASS_H
#define CLASS_H
#include<iostream>
#include<functional>
#include <memory>
#include <map>
#include <stdarg.h>
using namespace std;
class ClassMappingObject
{
    
    
    public:
    virtual void classinit()=0;
    virtual ~ClassMappingObject()=default;
};

using RegisterFunc = std::function<std::unique_ptr<ClassMappingObject>()>;
inline std::map<std::string ,RegisterFunc> objectMap;
static void registerObject(const std::string& name,RegisterFunc func) {
    
    
    objectMap[name] = func;
}

template <typename T>
T* createObject(const std::string& name) {
    
    
    for(auto m: objectMap)
    {
    
    
        // std::cout<<"keys: "<<m.first<<std::endl;
    }
    if (objectMap.find(name) == objectMap.end()) {
    
    
        return nullptr;
    }
    auto ptr = objectMap[name]();
    // 从基类动态转换为外部需要的类型
    return dynamic_cast<T*>(ptr.release());
}

//第一种宏定义
template <typename T1>
std::unique_ptr<ClassMappingObject> class_make_unique() {
    
    
    auto* ptr = new T1;
    return std::unique_ptr<ClassMappingObject>(dynamic_cast<ClassMappingObject*>(ptr));
}
#ifndef REGISTER_CLASS
#define REGISTER_CLASS(Type)\
static struct _ObjectRegisterTask##Type {
      
       \
    _ObjectRegisterTask##Type() {
      
       \
        registerObject(#Type,class_make_unique<Type>); \
    }; \
} _task##Type; // NOLINT
#endif

//第二种宏定义
struct RegisterTask {
    
    
    RegisterTask( string a) {
    
    
        std::cout<<a<<std::endl;
    }
    static string registerfun(const std::string& name,
        std::function<std::unique_ptr<ClassMappingObject>()> func) {
    
    
        registerObject(name,func);
        return name;
    }
};

#ifndef REGISTER_CLASS_2
#define REGISTER_CLASS_2(Type)\
static RegisterTask  task##Type(RegisterTask::registerfun(#Type,class_make_unique<Type>));
#endif
#endif

2.3 Per category

#include"class.h"
#include"F.h"

class Per:public F,public ClassMappingObject
{
    
    
    public:
    void classinit() //实现ClassMappingObject中函数进行初始化
    {
    
    
        tem=10;
        std::cout<<"Per classinit"<<std::endl;
    }
    virtual void fun() //实现F中虚函数进行执行业务
    {
    
    
        std::cout<<"Per fun:"<<tem<<std::endl;
    }
    private:
        int tem=0;
};

//进行注册
// REGISTER_CLASS(Per);
 REGISTER_CLASS_2(Per)

2.4 Per1 class

#include"class.h"
#include"F.h"
class Per1:public F,public ClassMappingObject
{
    
    
    public:
    void classinit() //实现ClassMappingObject中函数进行初始化
    {
    
    
        tem=10;
        std::cout<<"Per1 classinit"<<std::endl;
    }
    virtual void fun() //实现F中虚函数进行执行业务
    {
    
    
        std::cout<<"Per1 fun:"<<tem<<std::endl;
    }
    private:
        int tem=0;
};
//进行注册
// REGISTER_CLASS(Per1);
REGISTER_CLASS_2(Per1);

2.5 Student class

#include"class.h"
#include<vector>
#include"F.h"
class Student :public F, public ClassMappingObject
{
    
    
    public:
        Student(int a=10){
    
    tem = a;}
        virtual void fun()
        {
    
    
            std::cout<<"Student fun"<<tem<<std::endl;
        }
        
    public:
        void classinit()
        {
    
    
            tem=80;
            std::cout<<"Student classinit"<<std::endl;
        }
    private:
        float tem;

};
// REGISTER_CLASS(Student);
REGISTER_CLASS_2(Student);

3. Use

#include"classtet1.cpp"
#include"classtet2.cpp"
#include"classtet3.cpp"
#include"F.h"
int main(int argc, char const *argv[])
{
    
    
    /* code */
    F* ptr = createObject<F>("Per");  //获取基类类型,实现多态
    ptr->fun();
    return 0;
}

reference
reference
reference

Guess you like

Origin blog.csdn.net/u011573853/article/details/127830309