雪千渔Blog

  • 首页
  • 写写代码
    • dotNet
    • C++
    • Lua
    • Visual Basic
    • Java
    • Android
    • Web
  • DCC
    • Maya
    • Maya-Plug
    • AfterEffect
    • AfterEffect-Plug
    • PhotoShop-Plug
  • 游戏制作
    • Unity3D
    • UnrealEngine
    • 经验杂谈
    • 游戏设计
    • 自研引擎
    • 效果实现
  • 其他
    • 乱七八糟
    • 软件工具
    • 留言板
    • 自制素材
    • 关于我
  • 世界的尽头
雪千渔blog
唯有热爱,能抵漫长岁月
  1. 首页
  2. Coding
  3. C++
  4. 正文

C++自制反射系统(一):类型反射结构

2021年8月6日 812点热度 3人点赞 0条评论

Contents

  • 1 前言
  • 2 分析
  • 3 实现
    • 3.1 类型基础设计
    • 3.2 类型信息提交
    • 3.3 实例对象获取Type
    • 3.4 类型获取Type
    • 3.5 字符串获取Type

前言

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提交了

  1. 创建对象工厂方法的函数指针
  2. 基类Type,因为Object没有基类,所以nullptr
  3. 类型的名字,前面带上命名空间
  4. 标准库的类型信息
  5. 类型的大小

在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;
}

 

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: cpp 反射
最后更新:2021年8月16日

JomiXedYu

一名游戏玩家。

点赞
< 上一篇
下一篇 >

文章评论

取消回复

*

code

JomiXedYu

一名游戏玩家。

分类
  • AfterEffect / 6篇
  • AfterEffect-Plug / 1篇
  • Android / 1篇
  • C++ / 13篇
  • dotNet / 12篇
  • Lua / 4篇
  • Maya / 2篇
  • Maya-Plug / 1篇
  • Office-VSTO&VBA / 2篇
  • Unity3D / 14篇
  • UnrealEngine / 1篇
  • Visual Basic / 8篇
  • Web / 2篇
  • 乱七八糟 / 2篇
  • 效果实现 / 2篇
  • 经验杂谈 / 2篇
  • 自制素材 / 3篇
  • 计算机图形学 / 1篇
  • 软件工具 / 4篇
友情链接
  • DorinXL
  • 小博博客
  • 秋橘斋
文章目录
  • 前言
  • 分析
  • 实现
    • 类型基础设计
    • 类型信息提交
    • 实例对象获取Type
    • 类型获取Type
    • 字符串获取Type

COPYRIGHT © 2014-2021 雪千渔Blog. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

辽ICP备20006894号-1