添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Reflection:反射,这一特性在许多主流语言中都能找到,可以在运行时动态的获取类型信息。

一些人认为在cpp中编程时,可以规避掉使用反射,转而用模板来实现,或者使用反射就是程序设计出现了问题;要么就是有关于运行时反射对于性能影响,都用到反射了还不如去用Java之类的说辞。但我认为,在cpp中还是有一些需求是可以用到运行时反射的:对象的序列化与反序列化、可以通过字符串查找类型与创建对象、运行时判断继承关系等功能。

反射信息属于一种元数据,这种元数据储存了类型相关的信息,如:类型名、基类、字段、方法、以及字段方法中的类型。这种在获取后也是储存在类中的,例如类的反射类型就是Type(C#)或Class(Java),字段的反射信息类就是FieldInfo等等。

以下文章储存反射信息的类将使用Type。

一般有三种方式获取反射信息Type实例:

第一种:使用字符串获取,Type::GetType("xxclass") 或 Class::forName("xxclass") 等等形式。

第二种:首先需要一个Object基类,该Object类的实例可以动态的获取一个元数据实例Type。也就是obj.GetType()

第三种:直接通过类型来获取,typeof(Object) 或 Object.class 等。

基本实现思路:使用全局变量初始化变量的自定义结构体构造函数,通过模板元编程与手动传入等手段获取类型信息,最后向全局元数据信息表提交数据。

类型基础设计

在Object中编写一个私有静态的,用于获取类型信息的方法。

class Object
    friend class Type;
private:
    static Type* __meta_type();

声明Type类型:

class Type final : public Object
    using c_inst_ptr_t = Object * (*)(const ParameterPackage&);
private:
    int id_;
    string name_;
    int structure_size_;
    Type* base_;
    c_inst_ptr_t c_inst_ptr_;
    const std::type_info& typeinfo_;

该Type类型记录了类型id,名字,sizeof的结果,基类对象指针,动态创建对象的工厂方法函数指针,标准库的type_info。

类型信息提交

那么如何生成这些Type实例呢?

使用在进main函数前,所有的全局变量都会初始化完毕这个特性,创建一个全局变量。这个全局变量将会自动收集相关信息后,提交或者注册到一个全局的Type表当中。我们可以轻松的利用C++17标准的静态内联变量来实现此功能。

class Object
 friend class Type;
private:
    static Type* __meta_type();
    static inline struct _ObjectInit {
        _ObjectInit() {
            Object::__meta_type();
    } _object_init;

静态的成员和全局变量本质是相同的,只不过静态成员的作用域与访问权限有所区别,所以依然可以参与全局的初始化。

该变量使用了自定义结构体类型,将会在初始化时自动构造。

Type* Object::__meta_type()
    static int id = -1;
    if (id == -1) {
        id = Type::Register(CreateInstance, nullptr, _T("JxCoreLib::Object"), typeid(Object), sizeof(Object));
    return Type::GetType(id);

生成一个静态变量id,默认为-1,代表没注册过该类型,如果不为-1,可以直接从Type中通过id快去获取类型。

向Type提交了

  • 创建对象工厂方法的函数指针
  • 基类Type,因为Object没有基类,所以nullptr
  • 类型的名字,前面带上命名空间
  • 标准库的类型信息
  • 类型的大小
  • 在Register之后返回一个内部Id,通过这个Id可以快速的获取Type实例,类似于缓存的作用。

    实例对象获取Type

    接下来在Object中添加一个虚函数:

    class Object
        friend class Type;
    private:
        static Type* __meta_type();
        static inline struct _ObjectInit {
            _ObjectInit() {
                Object::__meta_type();
        } _object_init;
        virtual Type* get_type() const;
    
    Type* Object::get_type() const
        return __meta_type();
    

    使用样例:

    Object obj;
    Type* type = obj.GetType();

    类型获取Type

    在Type中添加模板函数

    template<typename T>
    static inline Type* Typeof()
        return T::__meta_type();
    

    虽然__meta_type是类型的私有成员,但是Type是Object的友元类,可以直接访问。

    另外在全局声明一个,更加方便使用:

    template<typename T>
    Type* cltypeof()
        return Type::Typeof<T>();
    

    因为typeof关键字在g++中作为编译器扩展存在,可能会发生冲突,所以前面加了cl。

    使用样例:

    assert( Object().GetType() == cltypeof<Object>() )

    字符串获取Type

    字符串获取就是对全局Type表的遍历,找到对应的名字后返回。

    Type* Type::GetType(const string& str)
        for (auto& item : *g_types) {
            if (item->get_name() == str) {
                return item;
        return nullptr;
                                                    
                                    最后更新:2021年8月16日