我正在考虑为某些C ++类添加某种反射功能(这样我就不必使用RTTI了):获取方法的名称,声明的字段,类名......这种东西。< / p>
我正在考虑解析现有的源文件,获取已声明的字段列表&amp;方法,并重写每个源文件,将这种信息添加到每个类。
您如何看待这种方法?我想从头做一切,因为我认为这是一个很好的学习机会。你会建议其他方法吗?
// OFFTOPIC:Qt是怎么做到的?
答案 0 :(得分:3)
检查Boost.Mirror库。它还没有被Boost接受,所以你必须从Boost Vault获得download it。
图书馆仍处于开发阶段,文档很少,但通过研究provided examples,你可以实现自己想要的目标。
编辑:如果您真的要解析自己的C ++代码,那么您应该考虑clang
答案 1 :(得分:3)
我会叉gcc。
答案 2 :(得分:2)
是的,这就是Qt的工作方式 - 除了它没有将信息添加到类本身,它创建了一个名为元类的新类,其中包含有关该类的静态数据。出于显而易见的原因,这更好。
没有纯C ++方法可以提供全自动反射 - 语言不允许它。有许多尝试,包括Boost.Mirror和Boost.Reflection,但它们都需要在源代码中添加样板。
答案 3 :(得分:1)
除非您想修改C ++编译器或依赖供应商扩展,否则您将需要一堆构建数据结构的CPP宏。
答案 4 :(得分:1)
您可能会发现gccxml值得一看。它(例如)将this转换为this,这意味着您只需要解析XML而不是C ++。
有一个有趣的SP&amp; E paper,它描述了将gccxml与修改后的链接器结合使用,以“以干净,非侵入的方式为C ++应用程序提供类似Java反射的功能”。
答案 5 :(得分:1)
更改编译器以生成静态GetClass方法,为每个已定义的类返回指向类对象的指针。
更改编译器/链接器以获取所需的元数据,并将其填充到生成的可执行映像的特殊部分/符号中 - 就像添加调试符号一样。
GetClass会使用(读取/加载/缓存?)上面的元数据。
是的。这是很多工作。 (还有一个很好的副作用就是让你几乎不用去消除头文件了 - 因为这些信息现在可以直接从图像中拉出来)
答案 6 :(得分:1)
C ++不支持反射。来自boost和RTTI的努力非常有限,并且已经完成了一半。我不推荐他们。
你提到过你可以从scatch开始。那么你可以用lex / yacc或ANTLR编写一个C ++词法分析器。相当多的工作,但你会学到很多东西。
如果编写解析器对您来说是一项艰巨的任务,那么还有一些其他选项可以获取类的元数据。 Microsoft提供了提供符号信息的DIA SDK。 Doxygen可以生成XML文件,您可以解析这些文件以获取字段名称,类的方法名称。我在解析doxygen XML文件方面取得了一些成功。
如果您只使用Microsoft平台,可行的解决方案是使用类型库(TLB)。它要求您将类转换为MS IDL中的接口。 MIDL将IDL编译为.tlb,您的应用程序可以在运行时加载.tlb文件。您的应用程序可以通过ITypeInfo接口,属性和方法获取有关该类的几乎所有信息。
答案 7 :(得分:1)
遵循格林斯普恩的第十条法则,你很高兴:只需实施一个临时的,非正式指定的,错误缠身的,缓慢实施的一半Common Lisp。选择一半支持实现反射。 :)
或者,这是一个想法:
在构建中打开地图文件(以及可能的程序集生成)。实现生成代码以创建动态库的应用程序。您应该能够从源或其中一个构建工件获取有关类的所有静态信息(方法名称,参数,类型等)。使用映射或程序集,您应该能够找到函数地址,虚函数指针偏移量,全局变量地址,变量偏移量,有关堆栈和寄存器分配变量的信息等等。从这些信息中构建一个库,其中包含通过传递类型名称,指针,函数名等来获取所有这些信息的调用。
现在,在C ++中,编写一个包含函数和宏的库,允许您将唯一的Id编译成用于识别函数启动的代码,所有反射调用,反射调用时的EIP偏移等。使用内联汇编宏如果需要,通常在身份证之后,在适当的位置,如果需要,可以在必要时与NOP一起留出一些指示。此外,提供桥接库函数,允许反射功能处理它可以内联的内容(比如获取函数的地址),而不必调用构建在构建后步骤中的动态库。
最后,编写一篇post-post构建反射链接器。我建议“kniltsoPostlink”,但这取决于你。在此步骤中搜索您的唯一ID(我是否提到过,您可以轻松制作ID GUID,以便在二进制文件中搜索它们?),以及ID标记对函数的反射调用,或者类的定义等,在那里放置足够的数据(在编写反射器库时可以很容易地确定的格式),然后在调用反射器库之前在ID中重写调用,以便它从那些数据位中提取所需的参数,或者只是把数据位放在那里,如果适用的话,我真的不能提前知道,但是当你写它时,这些小细节就会突然出现在你面前。
无论如何,我知道我没有提供太多代码,而且一旦我有足够的业余时间,我实际上打算在某个时候开始一个项目。我的意思是,每个小部分应该非常简单,所以当你逐步进行时,每个小部分都应该变得清晰,只要你遵循这里列出的指导方针。有些可能实际上比我在这里描述的更简单,因为这是最糟糕的情况。您甚至可以在不必重新编写代码到反射器调用的情况下离开;只需将数据放在适当的位置,就可以让库根据需要提取这些位而无需进一步的信息。
我很高兴你问过;我现在很忙,但是如果你有一个免费的夜晚,我想这将是第一个版本的良好开端,我会很乐意尽快投入。
)
答案 8 :(得分:0)
也许您可以使用typeinfo库,现在您可以在运行时使用对象类。例如:
#include<iostream>
#include<typeinfo>
class A{};
int main()
{
A a;
std::cout<<typeid(a).name();
}
您可以在以下位置查看更多内容: http://www.cplusplus.com/reference/std/typeinfo/
[]单曲