首页 / 知识
如何将反射添加到C ++应用程序?
2023-04-14 01:27:00

How can I add reflection to a C++ application?我希望能够内省一个C ++类的名称,内容(即成员及其类型)等。我在这里说的是原生C ++,而不是托管C ++,它有反射。 我意识到C ++使用RTTI提供一些有限的信息。 哪些额外的库(或其他技术)可以提供此信息? 您需要做的是让预处理器生成有关字段的反射数据。此数据可以存储为嵌套类。
首先,为了使它在预处理器中更容易和更清晰,我们将使用类型化表达式。类型化表达式只是将类型放在括号中的表达式。因此,不是写
接下来,我们定义一个
因此,使用Boost.PP,我们迭代每个参数并生成如下数据:
这样做是生成一个常量
现在迭代字段我们使用访问者模式。我们创建一个从0到字段数的MPL范围,并访问该索引处的字段数据。然后它将字段数据传递给用户提供的访问者:
现在我们把它放在一起。以下是我们如何定义可反射的
这是一个使用反射数据迭代字段的通用
将
哪个输出:
瞧,我们刚刚用100行代码实现了C ++中的反射。
游泳有两种 使用C ++是不可能的。 使用 如果您正在寻找方法来完成1),比如查看一个类有多少方法,或者喜欢获取类id的字符串表示,那么我担心没有标准的C ++方法。你必须使用其中之一
C ++的设计考虑了速度。如果你想要高级检查,比如C#或Java,那么我恐怕不得不告诉你没有办法没有办法。 我会喜欢小马,但小马不是免费的。 :-P http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI就是你要得到的。您正在考虑的反思 - 在运行时可用的完全描述性元数据 - 默认情况下C ++不存在。
这是完全错误的。实际上,术语"RTTI"是由C ++标准创造的。另一方面,RTTI在实现反射方面并没有走得太远。 信息确实存在 - 但不是以您需要的格式存在,并且仅在您导出类时才存在。这适用于Windows,我不了解其他平台。使用存储类说明符,例如:
这使得编译器将类定义数据构建到DLL / Exe中。但它不是一种可以随意用于反射的格式。 在我的公司,我们构建了一个解释这些元数据的库,并允许您反映一个类,而无需在类本身中插入额外的宏等。它允许按如下方式调用函数:
这有效地做到了:
Invoke(this_pointer,...)函数具有可变参数。显然,通过以这种方式调用函数,你可以绕过诸如const-safety之类的东西,因此这些方面被实现为运行时检查。 我确信语法可以改进,它只适用于Win32和Win64到目前为止。我们发现它对于为类提供自动GUI接口,在C ++中创建属性,在XML之间进行流式传输等等非常有用,并且不需要从特定的基类派生。如果有足够的需求,也许我们可以将其打造成释放形状。 您需要查看您要执行的操作,以及RTTI是否满足您的要求。我已经为一些非常特殊的目的实现了我自己的伪反射。例如,我曾经希望能够灵活地配置模拟输出的内容。它需要向要输出的类添加一些样板代码:
第一个调用将此对象添加到过滤系统,该系统调用 然后,在配置文件中,您可以执行以下操作:
通过一些涉及 你想用反射做什么? 您可以使用Boost类型traits和typeof库作为有限形式的编译时反射。也就是说,您可以检查和修改传递给模板的类型的基本属性。 我建议使用Qt。 有开源许可证和商业许可证。 编辑:CAMP不再维护;有两个叉子可供选择:
CAMP是MIT许可的库(以前称为LGPL),它为C ++语言添加了反射。它不需要编译中的特定预处理步骤,但必须手动进行绑定。 目前的Tegesoft库使用Boost,但也有一个使用C ++ 11的fork,不再需要Boost。 在C ++中还有另一个用于反射的新库,称为RTTR(运行时类型反射,另请参见github)。 该接口类似于C#中的反射,它可以在没有任何RTTI的情况下工作。 我做过类似你曾经做过的事情,虽然可以获得一定程度的反思和访问更高级别的功能,但维护上的头痛可能不值得。我的系统用于通过委托将UI类与业务逻辑完全分离,类似于Objective-C的消息传递和转发概念。这样做的方法是创建一些能够映射符号的基类(我使用字符串池但你可以使用枚举,如果你更喜欢速度和编译时错误处理而不是总灵活性)来实现函数指针(实际上不是纯函数指针,但类似于Boost与Boost.Function的相似之处 - 我当时没有访问权限。只要您有一些能够表示任何值的公共基类,您就可以对成员变量执行相同的操作。整个系统是一个毫不掩饰的密钥值编码和委派的冲突,有一些副作用可能值得花费足够的时间来使每个使用该系统的类匹配其所有方法和成员与合法调用:1)任何类都可以在任何其他类上调用任何方法,而不必包含头文件或编写伪基类,因此可以为编译器预定义接口; 2)成员变量的getter和setter很容易实现线程安全,因为更改或访问它们的值总是通过所有对象的基类中的2个方法来完成。 它还导致了做一些非常奇怪的事情的可能性,否则这些事情在C ++中并不容易。例如,我可以创建一个包含任意类型的任意项(包括其自身)的Array对象,并通过将消息传递给所有数组项并收集返回值(类似于Lisp中的map)来动态创建新数组。另一个是键值观察的实现,我可以设置UI来立即响应后端类成员的变化,而不是不断地轮询数据或不必要地重新绘制显示。 您可能更感兴趣的是,您还可以转储为类定义的所有方法和成员,并以字符串形式进行转储。
系统的缺点可能会阻止您打扰:添加所有消息和键值非常繁琐;它比没有任何反射慢;你会变得讨厌在你的代码库中以狂暴的热情看待 至于如何实现这样的事情:只使用共享和弱指针到一些公共基础(我的想象力被称为"对象"),并派生出你想要使用的所有类型。我建议安装Boost.Function而不是像我那样做,这是一些自定义的垃圾和大量丑陋的宏来包装函数指针调用。由于所有内容都已映射,因此检查对象只需迭代所有键即可。由于我的类基本上只使用C ++就可以直接使用Cocoa,如果你想要这样的东西,那么我建议使用Cocoa文档作为蓝图。 我从C ++时代就知道的两个类似反射的解决方案是: 1)如果能够从"对象"基类派生所有类,则使用RTTI,它将为您提供构建类似反射的行为的引导程序。该类可以提供一些方法,如GetMethod,GetBaseClass等。至于这些方法如何工作,您需要手动添加一些宏来装饰您的类型,在幕后创建类型的元数据,以提供GetMethods等的答案。 2)如果您有权访问编译器对象,则另一个选项是使用DIA SDK。如果我没记错的话,这可以让你打开pdbs,它应该包含C ++类型的元数据。它可能足以满足您的需求。此页面显示了如何获取类的所有基类型。 这两种解决方案虽然有点难看!没有什么比C ++更能让你欣赏C#的奢侈品了。 祝好运。 开箱即用的C ++不支持反射。这很令人难过,因为它使防御性测试成为一种痛苦。 有几种做反射的方法: 第一个链接看起来最有希望(使用mod's clang),第二个链接讨论了许多技术,第三个是使用gcc的不同方法: http://www.donw.org/rfl/ https://bitbucket.org/dwilliamson/clreflect https://root.cern.ch/how/how-use-reflex 现在有一个C ++反射工作组。查看C ++ 14 @ CERN的新闻:
编辑13/08/17: 自原始帖子以来,反思已经有了许多潜在的进步。以下提供了更多细节,并讨论了各种技术和状态: 然而,在不久的将来,C ++中的标准化反射方法看起来并不乐观,除非社区对支持C ++中的反射有更多的兴趣。 以下根据上次C ++标准会议的反馈详细介绍了当前状态:
编辑13/12/2017 反思看起来正朝着C ++ 20或更高的方向发展,可能是TSR。然而运动很慢。
编辑15/09/2018 已将TS草案发送给国家机构进行投票。 可在此处找到该文本:https://github.com/cplusplus/reflection-ts 编辑11/07/2019 反射TS是完整的功能,并在夏季(2019年)进行评论和投票。 元模板编程方法将被更简单的编译时代码方法所取代(未在TS中反映出来)。
编辑:更新了截至2017年2月7日的断开链接。 我想没人提到这个: 在欧洲核子研究中心,他们使用C ++的全反射系统: CERN Reflex。它似乎工作得很好。 这个问题现在有点老了(不知道为什么我今天仍然会遇到旧问题)但我正在考虑引入编译时反射的BOOST_FUSION_ADAPT_STRUCT。 你可以将它映射到运行时反射当然,它不会太容易,但它可以在这个方向,而它不会反过来:)
我真的认为封装 我想你可能会发现Dominic Filion的文章"在C ++中使用模板反射"。这是在游戏编程宝石5的1.4节。不幸的是我没有我的副本,但寻找它,因为我认为它解释了你的要求。 反射主要是关于编译器决定留下什么作为运行时代码可以查询的代码中的脚印。 C ++以不付你不使用的东西而闻名;因为大多数人不使用/想要反射,所以C ++编译器通过不记录任何内容来避免成本。 因此,C ++不提供反射,并且像其他答案所指出的那样,自己"模拟"它并不容易。 在"其他技术"下,如果您没有带反射的语言,请获取一个可以在编译时提取所需信息的工具。 我们的DMS软件再造工具包是通过显式语言定义参数化的通用编译器技术。它有C,C ++,Java,COBOL,PHP的语言定义...... 对于C,C ++,Java和COBOL版本,它提供对解析树和符号表信息的完全访问。该符号表信息包括您可能想要从"反射"获得的数据类型。如果您的目标是枚举某些字段或方法集并对它们执行某些操作,则可以使用DMS根据您在符号表中以任意方式找到的内容来转换代码。 Ponder是一个C ++反射库,用于回答这个问题。我考虑了这些选项,并决定自己做,因为我找不到一个勾选了我所有的盒子。 虽然这个问题有很好的答案,但我不想使用吨的宏,或者依赖Boost。 Boost是一个很棒的库,但有许多小的定制C ++ 0x项目更简单,编译时间更短。能够在外部装饰类也有一些优点,比如包装一个没有(但是?)支持C ++ 11的C ++库。它是CAMP的分支,使用C ++ 11,不再需要Boost。 查看Classdesc http://classdesc.sf.net。它以类"描述符"的形式提供反射,适用于任何标准C ++编译器(是的,它已知可以与Visual Studio以及GCC一起使用),并且不需要源代码注释(尽管存在一些编译指示来处理棘手的情况)。它已经开发了十多年,并用于许多工业规模项目。
你可以在这里找到另一个图书馆:http://www.garret.ru/cppreflection/docs/reflect.html 我也对我的项目的反思感兴趣,发现这个库,我还没有尝试过,但尝试过这个家伙的其他工具,我喜欢他们的工作方式:-) 当我想用C ++进行反思时,我读了这篇文章,并根据我在那里看到的内容进行了改进。对不起,没法。我不拥有结果......但是你可以得到我拥有的东西并从那里开始。 我正在研究,当我觉得它时,使用inherit_linearly方法来更容易地定义可反射类型。我实际上已经相当远了,但我还有很长的路要走。 C ++ 0x中的更改很可能在这方面提供了很多帮助。
看起来C ++仍然没有这个功能。 搜索一些宏或自己创建。 Qt也可以帮助反射(如果可以使用)。
即使在c ++中不支持开箱即用的反射,也不难实现。 文章详细解释了如何实现一个非常简单和基本的反射系统。授予它不是最健康的解决方案,并且还有粗糙的边缘需要整理,但是对于我的需求来说已经足够了。 底线 - 如果正确完成,反射可以得到回报,并且在c ++中完全可行。 我想宣传自动内省/反射工具包"IDK"的存在。它使用像Qt这样的元编译器,并将元信息直接添加到目标文件中。它声称易于使用。没有外部依赖。它甚至允许您自动反映std :: string,然后在脚本中使用它。请看IDK
如果你正在寻找相对简单的C ++反射 - 我从各种来源收集宏/定义,并评论它们如何工作。你可以下载标题 https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h 一组定义,以及它上面的功能:
https://github.com/tapika/TestCppReflect/blob/master/CppReflect.h
示例应用程序也驻留在git存储库中,在这里: 我将部分复制它并附上解释:
我使用pugi xml解析器将演示代码提取到xml中并从xml恢复。 因此,演示代码生成的输出如下所示:
也可以通过TypeTraits类和部分模板规范启用任何第三方类/结构支持 - 以类似于CString或int的方式定义自己的TypeTraitsT类 - 参见示例代码 https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195 此解决方案适用于Windows / Visual Studio。可以将它移植到其他OS /编译器,但还没有完成。 (问我是否真的喜欢解决方案,我或许可以帮助你) 此解决方案适用于具有多个子类的一个类的一次序列化。 但是,如果您正在搜索序列化类部件的机制,甚至控制反射调用产生的功能,您可以查看以下解决方案: https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel 更多详细信息可以在YouTube视频中找到:
C ++运行时类型反射 我试图更深入地解释c ++反射将如何工作。 示例代码如下所示: https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp
但这里的每一步实际上都会产生函数调用 它以路径的形式接收有关C ++数据类型,C ++属性名称和类实例指针的完整信息,并且基于该信息,您可以生成xml,json甚至通过Internet序列化该信息。 可以在此处找到此类虚拟回调函数的示例: https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp
请参见函数 但由于主题非常先进 - 我建议先查看视频。 如果您有一些改进意见,请随时与我联系。 C ++中的反射非常有用,如果你需要为每个成员运行一些方法(例如:序列化,散列,比较)。我带有通用解决方案,语法非常简单:
其中ENUMERATE_MEMBERS是一个宏,稍后将对此进行描述(更新): 假设我们为int和std :: string定义了序列化函数,如下所示:
我们在"秘密宏"附近有通用功能;)
现在你可以写了
因此,在结构定义中使用ENUMERATE_MEMBERS宏,您可以构建序列化,比较,散列和其他内容而无需触及原始类型,唯一的要求是为每个类型实现"EnumerateWith"方法,这是不可枚举的,每个枚举器(如BinaryWriter) 。通常,您必须实现10-20"简单"类型以支持项目中的任何类型。 这个宏应该在运行时对结构创建/销毁进行零开销,并且应该按需生成T.EnumerateWith()的代码,这可以通过使其成为模板内联函数来实现,因此这是唯一的开销。所有的故事都是为每个结构添加ENUMERATE_MEMBERS(m1,m2,m3 ...),而在任何解决方案中都必须实现每个成员类型的特定方法,所以我不认为它是开销。
更新:
对于这15行代码,您不需要任何第三方库;) 使用C ++ 20,您可以获得扩展语句,它允许您迭代聚合类型:
如果你声明一个指向这样的函数的指针:
您可以像这样在内存中为该函数指定一个位置(需要
要使用间接加载本地符号,可以在调用二进制文件(
对此的唯一要求( |
最新内容
相关内容
Python变量数据类型的转换
Python变量数据类型的转换,代码,数据,培训,信息,字符串,类型,变量,整数,浮点,函数,虽然Python是弱类型编程语言,不需要像Java或C语言那样还要Python变量的类型(弱类型语言)
Python变量的类型(弱类型语言),检测,代码,数据,培训,类型,变量,语言,赋值,数字型,字符串,在强类型的编程语言中,定义变量时要指明变量的类型,而Python的动态类型
Python的动态类型,数据,数字,对象,情况,对比,培训,赋值,字符串,元素,整数,在我们接触的对象中,有一类特殊的对象,是用于存储数据的。常见的该类python丰富的内置类型及相关操作
python丰富的内置类型及相关操作,数字,培训,索引,元素,切片,类型,操作,列表,嵌套,引号,python的内置类型如下:lString:字符串放在单引号、双引python 二次加工标准类型(包装)
python 二次加工标准类型(包装),标准,包装,位置,异常,时间,产品,培训,新增,方法,文件,包装:python为大家提供了标准数据类型,以及丰富的内置方python怎样获取json数据类型?
python怎样获取json数据类型?,培训,数据类型,类型,正则,火狐,以上,方法,更多,内容,列表,python中获取json不同数据类型的方法:1、获取"key":vpython如何获取列表里的数据类型?
python如何获取列表里的数据类型?,代码,信息,培训,类型,数据类型,表里,元素,语句,函数,对象,1、Python可以通过tpye()方法来判断list里的元知实数是不是python的数据类型?
实数是不是python的数据类型?,数字,标准,培训,实数,数据类型,数轴,复数,有限小数,无理数,虚数,实数是python的数据类型。实数,是有理数和无理Python可以做桌面应用程序吗
Python可以做桌面应用程序吗,平台,系统,较大,标准,培训,界面,桌面,文档,入门,开发者,python可以做桌面应用程序!目前比较主流的几个GUI平台:1python字典类型的数据怎么保存
python字典类型的数据怎么保存,数据,培训,字典,中间,类型,文件,相似性,变量,算法,效率,在使用python编程过程中,我们往往需要借助字典来提高编python中如何定义int类型
python中如何定义int类型,标准,数字,数据,培训,基础,整数,数据类型,赋值,布尔,类型,标准数据类型python3中有六个标准的数据类型:Number(数字)pythondict是什么类型
pythondict是什么类型,培训,数字,字典,类型,数据类型,冒号,括号,逗号,字符串,容器,python中的dict表示的字典数据类型。字典是另一种可变容器