c++ 完备的运行时类型信息(动态类型信息)
发布时间 - 2026-01-11 02:28:26 点击率:次众所周知,码猿写代码,自然要求严谨周密,殊不知想象力也很重要。本座阅码几十年,很是感概很多码猿的脑洞被大大禁锢,鲜有人能越雷池一步,特别是c++的同学,连同委员会的那一坨老头子,都很让人无语至极,出自这些人的作品,都是一个死鱼眼睛样子,千人一面,毫无灵动之生趣可言。stl,boost这些库都是这样子(虽然它们确实可以完成大多数日常任务),更别说其他的库,没有什么让人耳目一新之处。

就说说动态类型信息这块,又或者说是反射。自然,语言本身提供的废物type_info就懒得说了,除了证明c++也东施效颦,也能支持动态信息之外,就别无用处了,有谁会正儿八经的用type_info做点正儿八经的事情呢。因此,各路人马纷纷上阵,都要弥补c++在运行时类型信息上的缺失。因为类型的反射信息实在太重要,或者说,反射的用武之地太多太多,表面上很多事情不需要反射,或者字面代码上就看不到反射的痕迹,但是内里的实现,大把大把的反射在发光发热。c++坚持不在动态信息上给予一点点多余的支持,并不表示c++就不需要反射了,看看标准库这个极力回避动多态的典范,是一个怎样的失败作品,嗯,这个以后再谈吧。假如stl一开始就没有如此大力排斥动多态,你看看就连内存分配的allocator都可以做到静态类型信息里面(最新版的c++终于也要接受多态的allocator,c++界居然一片欢呼鼓舞,真是悲哀),今时今日的c++就不会在很多领域上到处割地求和。
总的来说,现在市面上的c++反射库,都是侵入式,都学着mfc那一套,都是要求继承自一个基类Object,然后才能对外提供反射信息的功能,先不说它们提供的类型信息是否完备,这样子就把用途广泛限制死在一个很窄很窄的小圈子里面了。这些反射库,1、不能反射基本类型,int、char、double、const char*、……等;2、不能反射非继承自Object的class或者struct,3、也不能反射模板类,比如vector<int>、list<vector<vector<int>>>。虽然typeid千般弱鸡,但也非一无是处,起码非侵入、平等、多态。所以,理想的反射,应该像c++原生的typeid那样无色无味:1、非侵入式的;2、可以对所有的类型都提供反射,基本类型、非Object系的struct或者class、template类型的;3、多态的,只要改类型需要运行时的类型识别,那么就返回其本身的类型(子类),而非字面上的声明类型;4、支持类型参数,也即是说,以类型传递给该函数时,就返回相应的类型信息对象。
说得具体一点,我们要求的反射库是这样子的。当然,首先要有一个类型信息对象TypeInfo,里面装满了关于对于类型的所有详细信息。如下所示:可以猜到这种反射下框架,只支持单继承,这是故意的。
struct TypeInfo
{
public:
template<typename Args>
void ConstructObject(void* obj, MemoryAllocator* alloc, Args&& args)const;
bool IsDerviedOf(const TypeInfo* base)const;
public:
virtual TIType GetTIType()const = 0;
virtual const InterfaceMap* GetInterfaces()const;
virtual jushort GetMemorySize()const;
virtual ConstText GetName() const;
virtual AString GetFullName()const;
virtual jushort GetAlignSize() const;
virtual ConstText GetSpaceName()const;
virtual const TypeInfo* GetBaseTypeTI()const;
virtual const TypeInfo* GetPointeedTI()const;
virtual size_t GetHashCode(const void* obj)const;
virtual bool IsValueType()const { return true; }
virtual bool IsClass()const { return true; }
virtual bool DoInitAllocator(void* obj, MemoryAllocator* memAlloc)const;
virtual bool NeedDestruct()const { return false; }
virtual void DoDefaultConstruct(void* obj)const;
virtual bool CanDefaultConstruct()const { return true; }
virtual void DoAssign(void* dest, const void* src)const;
virtual bool Equals(const void* objA, const void* objB)const;
virtual void DoDestruct(void* obj)const;
};
然后,就要有一个函数TypeOf,应该是两个,一个是无参数的类型模板函数,可以这样调用,TypeOf<type>();一个是有一个参数的类型模板函数,可以这样调用,TypeOf(obj)。不管是那一个,其返回结果都是const TypeInfo*。TypeOf的要做到的事情是,对于每一种类型,有且只有一个唯一的TypeInfo对象与之对应,不管是template的还是非template的;比如,以下的几个判断必须成立。
TypeOf<int>() == TypeOf<int>();
TypeOf<int>() == TypeOf(n); //n为整型
TypeOf<vector<int>>() == TypeOf(nums);//nums的类型为vector<int>
Object* a = new ObjectA; TypeOf(a) == TypeOf<ObjectA>();
其实这里面的原理也没什么神奇,无非就是trait配合sfine,接下来就全部都是苦力活,就是为每一种类型都专门特化一个详细描述的类型对象,用宏可以节省大量的代码。但是整个反射库,本座前前后后重构了十几次,现在也还在重构之中,终究还是解决了开发上所遇到的各种事情。比如,序列化(支持指针、支持多态)、对象与xml的互换、对象与json的互换、数据库表读写对象、格式化、Any类型、非侵入式接口、消息发送、字符串生成对象等等。
其实现方式,概括起来,就是引入间接层元函数TypeInfoImp专门用于返回一个类型type,type里面有一个GetTypeInfo()的函数。然后TypeOf调用TypeInfoImp里的type的GetTypeInfo()最终得到TypeInfo对象。代码如下所示。
template<typename Ty> struct TypeInfoImp
{
typedef Ty type;
static const bool value = THasGetTypeInfoMethod<Ty>::value;
};
template<typename Ty>
struct TypeInfoImp<const Ty> : public TypeInfoImp<Ty>
{
typedef typename TypeInfoImp<Ty>::type type;
static const bool value = TypeInfoImp<Ty>::value;
};
template<typename Ty>
const TypeInfo* TypeOf()
{
typedef typename TypeInfoImp<Ty>::type TypeInfoProvider;
return TypeInfoProvider::GetTypeInfo();
}
template<typename Ty>
const TypeInfo* TypeOf(const Ty& obj)
{
typedef typename IsRttiType<Ty>::type is_rtti; //又是间接层,对动态类型和非动态类型分别处理
return ImpTypeOf(obj, is_rtti());
}
template<>
struct TypeInfoImp < bool >
{
static const bool value = true;
typedef TypeInfoImp<bool> type;
static TypeInfo* GetTypeInfo();
};
TypeInfo* TypeInfoImp<bool>::GetTypeInfo()
{
static TypeInfo* ti = CreateNativeTypeInfo<bool>("bool");
return ti;
}
可能可以有简洁的方式,比如不需要引入TypeInfoImp,但是实际最终证明TypeInfoImp的方式最具灵活性也最能节省代码。最起码,它在自定义的struct或者class就很方便,只要改struct内部包含一个GetTypeInfo()的函数,它就可以被纳入TypeOf体系中,非常方便。对于模板类型的TypeInfoImp,就要用到哈希表了。比如,对于std::paira的类型信息,如下实现,
template<typename FstTy, typename SndTy>
struct TypeInfoImp < std::pair<FstTy, SndTy> >
{
static const bool value = true;
typedef TypeInfoImp < std::pair<FstTy, SndTy> > type;
static TypeInfo* GetTypeInfo()
{
ParamsTypeInfo<FstTy, SndTy> args;
return PodPair::LookupTemplateTypeInfo(args);
}
};
提取其类型参数的const TypeInfo*,生成数组。用此数组到PodPair的哈希表里面查找,如果哈希表中以有此类型数组参数的对象就返回,否则见创建一个添加一条哈希条目,然后返回。每一个泛型类型,比如vector,list,pair都有一个属于自己的哈希表。
打完收工。原理很简单,但是对于工业级的反射库,要考虑很多细节,比如,TypeInfo对象的内存管理;怎么为enum类型生成一堆字符串,以支持字符串和enume值的互相转换;生成并保存class的构造函数和析构函数指针;命名空间的支持;*C#里面的attribute;如何以最方便的方式生成成员字段或者成员函数信息等等,一句话,就是他妈的体力活。但是,回报是很丰盛的,这里的苦力活做完之后,程序的其他地方上,基本上,就没有什么重复相似的代码,一切的体力工作全部就可以压在类型信息这里了。
# c++
# 运行时类型信息
# 都是
# 多态
# 这样子
# 让人
# 太多
# 不需要
# 就不
# 就没
# 所示
# 每一种
# 有一个
# 自己的
# 重构
# 是一个
# 本座
# 特化
# 这是
# 有什么
# 几个
# 都有
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何在新浪SAE免费搭建个人博客?
,交易猫的商品怎么发布到网站上去?
胶州企业网站制作公司,青岛石头网络科技有限公司怎么样?
Laravel如何集成第三方登录_Laravel Socialite实现微信QQ微博登录
如何实现建站之星域名转发设置?
Android中AutoCompleteTextView自动提示
Laravel Docker环境搭建教程_Laravel Sail使用指南
javascript中的try catch异常捕获机制用法分析
Edge浏览器怎么启用睡眠标签页_节省电脑内存占用优化技巧
在Oracle关闭情况下如何修改spfile的参数
如何在云主机快速搭建网站站点?
html5audio标签播放结束怎么触发事件_onended回调方法【教程】
JavaScript如何实现错误处理_try...catch如何捕获异常?
利用 Google AI 进行 YouTube 视频 SEO 描述优化
Laravel PHP版本要求一览_Laravel各版本环境要求对照
WEB开发之注册页面验证码倒计时代码的实现
Laravel怎么使用artisan命令缓存配置和视图
微博html5版本怎么弄发语音微博_语音录制入口及时长限制操作【教程】
如何在建站宝盒中设置产品搜索功能?
JavaScript 输出显示内容(document.write、alert、innerHTML、console.log)
奇安信“盘古石”团队突破 iOS 26.1 提权
网站制作大概多少钱一个,做一个平台网站大概多少钱?
如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?
Laravel怎么集成Log日志记录_Laravel单文件与每日日志配置及自定义通道【详解】
合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?
HTML 中动态设置元素 name 属性的正确语法详解
Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】
韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐
Laravel distinct去重查询_Laravel Eloquent去重方法
Laravel如何实现密码重置功能_Laravel密码找回与重置流程
Python文件流缓冲机制_IO性能解析【教程】
html5源代码发行怎么设置权限_访问权限控制方法与实践【指南】
Laravel如何实现数据库事务?(DB Facade示例)
企业网站制作这些问题要关注
Java解压缩zip - 解压缩多个文件或文件夹实例
JavaScript如何实现路由_前端路由原理是什么
简单实现jsp分页
如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程
为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】
如何快速搭建安全的FTP站点?
bing浏览器学术搜索入口_bing学术文献检索地址
php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】
Laravel如何使用查询构建器?(Query Builder高级用法)
武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?
Bootstrap CSS布局之列表
开心动漫网站制作软件下载,十分开心动画为何停播?
如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体
Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道
大学网站设计制作软件有哪些,如何将网站制作成自己app?
JavaScript如何实现继承_有哪些常用方法
上一篇:《逆战:未来》乘风破浪榴弹炮介绍
上一篇:《逆战:未来》乘风破浪榴弹炮介绍

