• c++ 反射类型


    来自: 

    实现代码===

    //
    // Created by lizhen on 2017/9/29.
    //
    
    #ifndef BOOST_ALL_CALLBACKFUNCTION_H
    #define BOOST_ALL_CALLBACKFUNCTION_H
    
    #include <iostream>
    #include <map>
    #include <string>
    using namespace std;
    
    typedef void* (*PTRCreateObject)(void);//定义一个函数指针类型,用于指向创建类实例的回调函数
    
    class ClassFactory{
    private:
        map<string,PTRCreateObject >map_classMap;
        ClassFactory(){};
    public:
        void *getClassByName(string className);
        void registClass(string name,PTRCreateObject method);
        static ClassFactory& getInstance();
    };
    
    ClassFactory& ClassFactory::getInstance() {
        static ClassFactory sLo_factory;
        return sLo_factory;
    }
    
    void* ClassFactory::getClassByName(string className) {
        map<string,PTRCreateObject >::const_iterator iter;
        iter = map_classMap.find(className);
        if(iter==map_classMap.end()){
            return NULL;
        }else{
            return iter->second();
        }
    }
    
    void ClassFactory::registClass(string name, PTRCreateObject method) {
        map_classMap.insert(pair<string,PTRCreateObject>(name,method));
    }
    
    class RegisterAction{
    public:
        RegisterAction(string className,PTRCreateObject ptrCreateFn){
            ClassFactory::getInstance().registClass(className,ptrCreateFn);
        }
    };
    
    //================================ClassA
    class TestClassA{
    public:
        void m_print(){
            cout<<"hello TestClassA"<<endl;
        }
    };
    TestClassA* createObjTestClassA(){
            return new TestClassA();
    }
    RegisterAction g_create_RegisterTestClassA("TestClassA",(PTRCreateObject)createObjTestClassA());
    //<-----
    
    //================================ClassB
    //test class B
    class TestClassB{
    public:
        void m_print(){
            cout<<"hello TestClassB"<<endl;
        }
    };
    TestClassB* createObjTestClassB(){
            return new TestClassB();
    }
    RegisterAction g_create_RegisterTestClassB("TestClassB",(PTRCreateObject)createObjTestClassB());
    //<---
    
    
    #define REGISTER(className)                                     
        className* objectCreater##className(){                      
            return new className();                                 
        }                                                           
        RegisterAction g_createrRegister##className(                
            #className,(PTRCreateObject)objectCreater##className)
    
    class classC{
    public:
        void m_print(){
            std::cout<<"hello classC"<<std::endl;
        }
    };
    
    REGISTER(classC);
    class Reflact{
    public:
        void run(){
            TestClassA* ptrObjA = (TestClassA*)ClassFactory::getInstance().getClassByName("TestClass");
            ptrObjA->m_print();
            //REGISTER(classC);
    
            classC* ptr_c = (classC*)ClassFactory::getInstance().getClassByName("classC");
            ptr_c->m_print();
        }
    };
    
    #endif //BOOST_ALL_CALLBACKFUNCTION_H

    =====

    转自http://blog.csdn.net/brighlee/article/details/72885219


    前言

    反射的概念:

    指程序在运行时,访问、检测和修改它本身状态或行为的一种能力。wikipedia

    简单的来说,就是一种自描述和自控制的能力。如果联想到镜子,就可以很好的理解,你能通过镜子看到自己,包括自己的动作,自己的外表。唯一不同的地方是,计算机语言的反射能力还包含对看到的自己采取措施。

    反射的作用

    在计算机编程语言中,反射机制可以用来:

    • 获取类型的信息,包括属性、方法
    • 动态调用方法
    • 动态构造对象
    • 从程序集中获得类型

    反射的缺点

    • 性能:反射可以理解成是一种解释操作,这个过程总是要慢于直接调用的。当然,性能问题的程度是可以控制的,如果程序在很少涉及的地方使用,性能将不会是一个问题。
    • 反射模糊了程序内部实际发生的事情,会比直接代码更加复杂。

    缺点不能掩饰其优点,针对不同的场景使用合理的技术才是最高境界。

    反射的使用场景

    • 序列化(Serialization)和数据绑定(Data Binding)
    • 远程方法调用(RMI)
    • 对象/关系数据映射(O/R mapping)

    关于c++的反射

    我们知道,Java是原生支持反射机制的,通过Class类可以通过名称获得类对象,进一步操作。Python也支持反射机制,可以通过globals()获取对象map,也可以通过inspect模块,提供了自省的方法。但是C++呢?C++原生不支持反射机制,RTTI(运行时类型识别)也仅仅提供了类型的判断。

    开闭原则是设计模式的原则之一,对修改是封闭,对扩展开放。一般来说,需要我们对类进行抽象,针对抽象的类进行编程。许多的设计模式中,为了能够满足这一点,我们常常使用一个配置文件,映射字符串与类型。然后通过反射机制获得字符串对应的对象,然后自动装配已达到易于扩展的目的。

    本文主要介绍两个小的场景如何实现C++反射。实际上,C++并不是对反射支持的很好,要支持动态和静态反射,还需要慢慢去寻找,我给出一些资料

    C++11 reflection library

    RTTR 库

    Boost.Mirror 库

    Mirror C++ reflection library

    本文讨论如何在C++中实现简单的反射。

    场景

    • C++序列化,与反序列化。序列化就是将对象编程二进制的形式存储在磁盘上,或者通过网络传输给另一台机器。反序列化就是序列化的逆过程。但是这个逆过程,必须要根据字符串来判断将二进制流转化成什么类型的对象。

    • 工厂模式,常常是根据一个字符串来获取想要的对象。但是为了满足开闭原则,我们不能简单的在工厂类中不断的修改生产函数来扩展不同的类型。这个时候,需要利用反射,使用抽象类。

    实现

    思路是:

    • 使用map,映射字符串和生产函数
    • 每次构造新类型时,将生产函数注册到map中
    • 工厂函数通过map获得生产函数,建造不同的对象

    方案一

    • map存储在Object抽象父类中
    • 使用ClassInfo辅助类型保存子类对象(包括了子类对象的构造函数)
    • map映射结构—->子类名称:ClassInfo*
    // Reflex.h 
    class Object{
    public:
        Object(){}
        virtual ~Object(){}
        static bool Register(ClassInfo *ci); // 注册函数
        static Object *CreateObject(string name);
    }
    
    using ObjectConstructorFn = Object *(*)(void); // 构造函数指针
    class ClassInfo {
    public:
        ClassInfo(const string classname, ObjectConstructorFn ctor)
            :class_name_(classname), m_object_constructor_(ctor) {
            Object::Register(this); // 注入到Object中
        }
    
        virtual ~ClassInfo(){};
        Object *CreateObject() const { // 返回当前类型的构造函数
            return m_object_constructor_ ? (*m_object_constructor_) : 0;
        }
    
        const string GetClassName() const {return class_name_;}
        ObjectConstructorFn GetConstructor() {return m_object_constructor_;} 
    
    private:
        string class_name_;
        ObjectConstructorFn m_object_constructor_; // 维护对象信息
    }
    
    
    ==============================================================
    // Reflex.cpp
    #include "Reflex.h"
    
    static unordered_map<string, ClassInfo *> *class_map = nullptr; // 延迟到第一次注册
    
    bool Object::Register(ClassInfo *ci) {
        if (!class_map) {
            class_map = new unordered_map<string, ClassInfo *>();
        }
    
        if (ci) {
            // 如果没有注册过
            string c_name = ci -> GetClassName();
            if (class_map -> find(c_name) == class_map -> end()) {
                class_map[c_name] = ci;
            }
            return true;
        }
    
        return false;
    }
    
    Object *Object::CreateObject(string name) {
        // 如果注册过就直接调用classinfo的createobject
        if (class_map -> find(name) != class_map.end())
            return class_map[name] -> CreateObject();
    
        return nullptr;
    }
    
    
    ==============================================================
    // test.cpp
    class A : public Object {
    public:
        A(){}
        ~A(){}
        ClassInfo *GetClassInfo const{ return &m_class_info_;}
    
        // 自定义生产函数
        static Object *CreateObject() {
            return new A;
        }
    
    protected:
        static ClassInfo m_class_info_;
    }
    
    // 最重要的一步,将当前类注册到Object中
    ClassInfo A::m_class_info_("A", A::CreateObject);
    
    int main() {
        Object *obj = Object::CreateObject("A");
        delete obj;
    
        return 0;
    }

    上面的代码实现了简单的反射机制,但是还不够好。每次构建类都需要写许多重复性的代码。而C++的宏为我们提供了很好的工具来简化重复性的代码。如下:

    // Reflex.h
    
    // 向类中添加 class_info 属性以及 CreateObject、GetClassInfo方法
    #define DECLEAR_CLASS(name) 
        protected: 
            static ClassInfo m_class_info_; 
        public:
            ClassInfo *GetClassInfo const; 
            static Object *CreateObject(); 
    
    // 实现CreateObject和GetClassInfo两个方法
    #define IMPLEMENT_CLASS_COMMON(name, func) 
        ClassInfo name::m_class_info_((#name), (ObjectConstructorFn) func); 
    
        ClassInfo *name::GetClassInfo() const 
        { return &name::m_class_info_;}
    
    // classInfo 属性的初始化
    #define IMPLEMENT_CLASS(name) 
        IMPLEMENT_CLASS_COMMON(name, name::CreateObject) 
        Object* name::CreateObject() 
        { return new name;}
    
    ==============================================================
    // test.cpp
    class B : public Object {
        DECLEAR_CLASS(B)
    public:
        B(){}
        ~B(){}
    };
    
    IMPLEMENT_CLASS(B)

    方案二

    • map存储在单例工厂类中
    • 定义RegisterAction类型完成注册动作
    • 同样使用宏将重复性的代码简化
    //工厂类的定义
    class ClassFactory{
    private:  
        map<string, PTRCreateObject> m_classMap ;  
        ClassFactory(){}; //构造函数私有化
    
    public:   
        void* getClassByName(string className);  
        void registClass(string name, PTRCreateObject method) ;  
        static ClassFactory& getInstance() ;  
    };
    
    //工厂类的实现
    //@brief:获取工厂类的单个实例对象  
    ClassFactory& ClassFactory::getInstance(){
        static ClassFactory sLo_factory;  
        return sLo_factory ;  
    }  
    
    //@brief:通过类名称字符串获取类的实例
    void* ClassFactory::getClassByName(string className){  
        map<string, PTRCreateObject>::const_iterator iter;  
        iter = m_classMap.find(className) ;  
        if ( iter == m_classMap.end() )  
            return NULL ;  
        else  
            return iter->second() ;  
    }  
    
    //@brief:将给定的类名称字符串和对应的创建类对象的函数保存到map中   
    void ClassFactory::registClass(string name, PTRCreateObject method){  
        m_classMap.insert(pair<string, PTRCreateObject>(name, method)) ;  
    }  
    
    //注册动作类
    class RegisterAction{
    public:
        RegisterAction(string className,PTRCreateObject ptrCreateFn){
            ClassFactory::getInstance().registClass(className,ptrCreateFn);
        }
    };
    
    ==============================================================
    
    //test class B
    class TestClassB{
    public:
        void m_print(){
            cout<<"hello TestClassB"<<endl;
        };
    };
    
    //@brief:创建类实例的回调函数
    TestClassB* createObjTestClassB{
            return new TestClassB;
    }
    //注册动作类的全局实例
    RegisterAction g_creatorRegisterTestClassB("TestClassB",(PTRCreateObject)createObjTestClassB);
    
    ==============================================================
    // 使用宏简化重复性代码
    
    #define REGISTER(className)                                             
        className* objectCreator##className(){                              
            return new className;                                           
        }                                                                   
        RegisterAction g_creatorRegister##className(                        
            #className,(PTRCreateObject)objectCreator##className)

    既然提到了宏,这里简单的复习一下,宏是由 #define 定义而来。在预处理阶段进行宏展开。它的格式是:

    #define <宏名> (<参数表>) <宏体> 
    #define N 2 + 2  // 仅仅是字符串替换
    #define N (2 + 2)  // 也是字符串 ,但是是(2 + 2)
    
    #define area(x) (x) * (x) // 带参的宏定义参会当作字符串直接替换
    
    三种特殊的符号:
    #               #define Conn(x, y) x##y     // 表示连接,数字,字符串都可以
    ##             #define ToString(x) #x      // 就是加上双引号 
    #@           #define ToChar(x) #@x       //就是加上单引号, 越界会报错

    总结

    反射在很多情况下都需要使用,应用场景比较广泛,希望读者能够仔细阅读代码。将反射机制使用在自己的工程里,实现一些设计良好的框架。另外,C++宏的使用可以极大的简化一些重复性的代码,可以仔细研究一下。

    =============

    来自http://blog.csdn.net/scythe666/article/details/51718864


    在 C++ 中实现反射

    反射(Reflection)是许多语言(如 C#,Java)都拥有的特性,用于在运行时获取类型信息,大大的提高了编程的灵活性,比如利用反射可以极大的简化 json/xml 解析、脚本绑定、属性编辑器等的实现。但是 C++ 并没有提供反射的支持,本文讨论在 C++ 中实现反射机制的一种方式。

    实现原理

    在 C# 等语言中,类型信息是在编译时由编译器解析并存储到元数据(Meta Data)中的,其中包括类的名称、方法、属性等信息。每新建立一个类,编译器就会自动生成对应的类型信息,类型信息会被关联在每一个对象上。

    但是在 C++ 中,编译器并没有为我们做这样的事情,我们只能自己将这些信息获取并保存下来。我们使用类似下面的结构存储类的相关信息:

    // 类信息
    class Type {
        // 类名
        std::string name;
    
        // 基类
        const Type* baseType;
    
        // 是否是枚举类型
        bool isEnum;
    
        // 构造方法
        std::vector<const Constructor*> constructors;
    
        // 属性
        std::unordered_map<std::string, const Field*> fieldsMap;
    
        // 方法,由于要支持重载,所以一个方法名对应多个方法
        std::unordered_map<std::string, std::vector<const Method*>> methodsMap;
    };
    // 引用类型
    enum class ReferType {
        None,           // 无引用类型(值类型)
        Refer,          // 左值引用
        RightRefer,     // 右值引用
    };
    
    // 修饰类型,比如 int*、const Type、float&
    class QualifiedType {
        // 基本类型
        const Type* type = nullptr;
    
        // 是否使用 const 修饰
        bool isConst = false;
    
        // 是否使用 volatile 修饰
        bool isVolatile = false;
    
        // 指针层级数量
        int pointerCount = 0;
    
        // 引用类型
        ReferType referType = ReferType::None;
    };
    
    // 属性
    class Field {
        // 属性名
        std::string name;
    
        // 所属的类
        const Type* ownerType;
    
        // 属性类型,注意是修饰类型
        const QualifiedType fieldType;
    
        // 是否为类属性
        bool isStatic;
    };
    
    // 方法
    class Method {
        // 方法名
        std::string name;
    
        // 返回类型
        const QualifiedType returnType = nullptr;
    
        // 所属的类
        const Type* ownerType = nullptr;
    
        // 参数列表
        std::vector<QualifiedType> paramTypes;
    
        // 是否为类方法
        bool isStatic;
    };

    通过在类声明中插入代码来注册类型信息,并大量使用模板和宏来简化代码,以 Constructor 为例,其实现如下:

    template<class T, class... Args>
    class ConstructorImpl : public Constructor {
    private:
        const Type* type;
    
    public:
        ConstructorImpl()
            : Constructor(typeof(T), { GetQualifiedType<Args>::Value() ... }) {
            static_assert(std::is_constructible<T, Args...>::value, "tried to register an undeclared constructor");
        }
    
        virtual Any Invoke(typename AsType<Args, Any>::Value... params) const override {
            return (Any)new T(std::forward<Args>((Args)params)...);
        }
    };

    注册方法信息的实现类似这样:

    template<class OwnerType, class ReturnType, class... Args>
    const Method* make_method(const std::string& name, ReturnType(OwnerType::*fun)(Args...)){
        return new MemberMethod<OwnerType, ReturnType, Args...>(name.substr(name.find_last_of(':') + 1), fun);
    }
    
    #define METHOD(fun) make_method(#fun, fun)

    使用示例

    下面演示了反射的枚举定义,和反射类型信息的描述

    REFLECT_ENUM(Sex, Male, Female)
    
    class PhoneNumber{
        BEGIN_TYPE(PhoneNumber)
            FIELDS(FIELD(&PhoneNumber::areaCode), FIELD(&PhoneNumber::number))
            CTORS(DEFAULT_CTOR(PhoneNumber), CTOR(PhoneNumber, const std::string&, const std::string&))
            METHODS(METHOD(&PhoneNumber::ToString))
        END_TYPE
    public:
        std::string areaCode;
        std::string number;
    
        PhoneNumber() {}
        PhoneNumber(const std::string& areaCode, const std::string& number) : areaCode(areaCode), number(number) {}
    
        std::string ToString() const { return areaCode + " " + number; }
    };
    
    class Person{
        BEGIN_TYPE(Person)
            FIELDS(FIELD(&Person::name), FIELD(&Person::sex), FIELD(&Person::phoneNumber), FIELD(&Person::totalNumber))
            CTORS(DEFAULT_CTOR(Person), CTOR(Person, const std::string&, float, Sex))
            METHODS(METHOD(&Person::Name), METHOD(&Person::GetSex), METHOD(&Person::GetPhoneNumber), METHOD(&Person::SetPhoneNumber), METHOD(&Person::GetTotalNumber))
        END_TYPE
    protected:
        std::string name;
        Sex         sex;
        PhoneNumber phoneNumber;
        static int  instanceCount;
    
    public:
        Person() { totalNumber++; }
    
        std::string&        Name() { return name; }
        Sex                 GetSex() const { return sex; }
        const PhoneNumber&  GetPhoneNumber() { return phoneNumber; }
        void                SetPhoneNumber(const PhoneNumber& phoneNumber) { this->phoneNumber = phoneNumber; }
        static int          GetInstanceCount() { return instanceCount; }
    };
    
    int Person::instanceCount = 0;

    然后可以像下面这样使用

    // 利用反射可以实现通用的 json/xml 转换
    auto p = JsonParser::Parse<Person>(R"(
    {
        "name": "John",
        "sex": "Female",
        "phoneNumber": { "areaCode": "+86", "number": "13888888888" }
    }
    )");
    
    // 通过反射调用构造方法
    auto newPhone = Type::GetType("PhoneNumber")->GetConstructor({qualified_typeof(const std::string&), qualified_typeof(const std::string&)})->Invoke(std::string("+86"), std::string("13000000000"));
    
    // 调用带参数的方法
    p->GetType()->GetMethod("SetPhoneNumber")->Invoke(p.get(), newPhone);
    
    // 调用类方法
    int instanceCount = typeof(Person)->GetMethod("GetInstanceCount")->Invoke(nullptr);
    
    // 获取属性值
    Sex sex = p->GetType()->GetField("sex")->Get(p.get());
    
    // 获取枚举值的名字
    std::cout << Enum::GetName(sex) << std::endl;
    
    // 输出所有属性的名字
    for (auto f : typeof(Person)->GetFields()){
        std::cout << f->GetName() << "," << std::endl;
    }

    不足之处

    • 由于大量使用模版技术,会导致代码膨胀
    • 侵入式的声明方式,必须对现有代码做改动才能使用,如果不需要运行时类型信息,可以改进成在一个单独的初始化方法里进行注册

    Demo 地址

    Github: https://github.com/Sleen/cpp_reflection

  • 相关阅读:
    setTimeout()和setInterval()的区别
    iOS开发小技巧
    iOS应用跳转到App Store评分
    前端小技巧-定位的活学活用之仿淘宝列表
    前端CSS
    用c# 开发html5的尝试,试用bridge.net
    Faster数据库研习,一
    五一劳动节,讲讲NEO智能合约的调试
    NEO GUI 多方签名使用
    NEO智能合约开发(二)再续不可能的任务
  • 原文地址:https://www.cnblogs.com/li-daphne/p/7613485.html
Copyright © 2020-2023  润新知