c++类对象反射、类成员数据反射

运行时反射

类对象反射

  • 首先实现一个内部静态变量的懒汉单例
    单例模式的使用

    template<class T>
    class Singleton{
    public:
        static T* instance(){
            static T m_instance;
            return &m_instance;
        }
    private:
        Singleton(){};
        ~Singleton(){};
        Singleton(const Singleton<T> &);
        Singleton<T>& operator= (const Singleton<T> &);
    };
    
  • 工厂类提供注册和创建类的函数

    使用map来记录类的名称和对应创建该类的函数指针,该指针所指函数 使用new创建相应的类对象并返回

    using create_obj = void*(*)(void);
    class ClassFactory{
    public:
        //注册函数
        void register_class(const std::string& className, create_obj method);
        //创建函数
        void* create_class(const std::string & className);
    private:
        ClassFactory(){}
        ~ClassFactory(){}
    private:
        //使用map来记录类的名称和对应创建类的函数
        std::map<std::string, create_obj> m_classMap;
        friend class utility::Singleton<ClassFactory>;
    };
    
  • 使用:创建类之前需要注册类

    int main(){
        //1.获取工厂单例
        ClassFactory* factory = Singleton<ClassFactory>::instance();
        //2.注册类
        factory->register_class("A", [](){
            A* a = new A;
            return static_cast<void*>(a);
        });
        //3.创建类
        A* a = static_cast<A*>(factory->create_class("A"));
        a->show();
        return 0;
    }
    
  • 实现注册类:将调用函数进行注册的步骤写成宏函数,在A.h末尾调用
    注意:宏定义不能放在命名空间内,因为宏定义属于预处理指令;在预处理阶段执行,而 在编译阶段执行。宏定义早在编译之前的预处理阶段就已执行完毕。

    class ClassRegister{
    public:
        ClassRegister(const std::string& className, create_obj method){
            auto factory = utility::Singleton<ClassFactory>::instance();
            factory->register_class(className, method);
        }
    };
    
    #define REGISTER_CLASS(className)\
        void* createObject##className(){\
            void* obj = new className();\
            return obj;\
        }\
        ClassRegister classRegister##className(#className, createObject##className)
    }
    
  • 在实际创建类时将void* 强转为A* 是不合理的,因为根本不知道是要使用的A类还是B类

    写一个A类、B类的公共基类:class Object,这样使用时直接用父类指针即可

    class Object{
    public:
        Object(){};
        virtual void show() = 0;
        virtual ~Object(){};//使用虚析构才能确保 正确调用派生类的析构函数
    };
    
    //使用
    int main(){
        ClassFactory* factory = Singleton<ClassFactory>::instance();
        Object* a = factory->create_class("A");
        a->show();
        return 0;
    }
    

类成员数据反射

  • 通过数据成员在类中的偏移量获取数据

    #include <string>
    #include <iostream>
    class Test{
    public:
        Test(const std::string& name, int age):m_name(name), m_age(age){
        }
    public:
        std::string m_name;
        int m_age;
    };
    int main(){
        Test t("yx", 12);
        std::cout<<*(reinterpret_cast<std::string*>(&t))<<std::endl;//yx
    
        auto offset = &(static_cast<Test*>(nullptr)->m_age);
        int age = *( reinterpret_cast<int*>((size_t)&t + (size_t)offset) );//(size_t)offset)是32,因为std::string占32字节
        std::cout<<age<<std::endl;
        return 0;
    }
    

    获取偏移量简写为如下宏(实际上标准库stddef.h有该函数offsetof)

    #define OFFSET(className, fieldName)\
        ((size_t)(&((className*)0)->fieldName))
    
  • 定义一个 字段数据结构

    保存 字段名、字段类型、字段在类中的偏移量

    class ClassField{
    public:
        ClassField(): m_name(""), m_type(""), m_offset(0){
        }
        ClassField(const std::string& name, const std::string& type, size_t offset):m_name(name), m_type(type), m_offset(offset){
        }
        ~ClassField(){}
    
    public:
        std::string m_name;
        std::string m_type;
        size_t m_offset;
    };
    
  • 字段的注册与获取

    注册就是 将类名:字段信息 保存到map中。获取就是从map中取出字段信息,然后根据其中的偏移量获取到成员变量的值。

    template <class T>
    inline void Object::get(const std::string &fieldName, T &value)
    {
        ClassFactory* factory = utility::Singleton<ClassFactory>::instance();
        auto field = factory->get_field(m_className, fieldName);//从map中找
        size_t offset = field->m_offset;
        value = *(T*)((size_t)(this)+offset);
    }
    

函数指针的使用

class Test{
public:
    int f2(int m){
        std::cout<<"Test2::ff "<<m<<std::endl;
        return m;
    }
};
int f1(int m){
    std::cout<<"ff "<<m<<std::endl;
    return m;
}
int main(){
    //1.普通函数指针
    using f1_ptr_type = int(*)(int);
    f1_ptr_type f1_ptr = f1;
    f1_ptr(3);
    //2.成员函数指针:使用function
    using f2_ptr_type = std::function<int(Test*, int)>;
    f2_ptr_type f2_ptr = &Test::f2;
    Test t;
    f2_ptr(&t, 4);
    //3.成员函数指针:通过对象调函数
    using f3_ptr_type = int(Test::*)(int);  
    f3_ptr_type f3_ptr = &Test::f2; 
    Test t2;
    (t2.*f3_ptr)(5);
}

编译期反射

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值