用C ++反思
我一直在使用Java工作多年。 在那些年里,我已经广泛(或者可能只是经常)使用reflection,并发现它有用且令人愉快。 但是8个月前我改变了我的工作,现在Java只是一个记忆,而我正在接受C ++。 所以现在我想知道C ++中是否有任何reflection机制。 我读过有关RTTI的内容,但我觉得这绝不是Java(或其他语言)reflection的强大function。 我开始认为在C ++中无法做到这一点。 我错了吗?
如果您正在寻找一种在运行时操作对象的完全通用的方法,当您在C ++编译时不知道它们的类型时,您基本上需要:
- 为类可能支持的每个function定义一个接口(具有所有纯虚方法的抽象基类,没有成员)。
- 每个类必须从它想要实现的所有接口(可能在其他类中)中虚拟inheritance。
现在,假设pFoo
将一个类型为IFoo*
的接口指针保存到某个对象x
(您不需要知道x
的具体类型)。 您可以通过以下方式查看此对象是否支持接口IBar
:
if (IBar* pBar = dynamic_cast(pFoo)) { // Do stuff using pBar here pBar->endWorldHunger(); } else { // Object doesn't support the interface: degrade gracefully pFoo->grinStupidly(); }
这种方法假设您在编译时知道所有相关接口 – 如果不这样做,您将无法使用普通的C ++语法来调用方法。 但很难想象调用程序不知道它需要什么接口的情况 – 关于我能想到的唯一情况是,如果你想通过交互式解释器公开C ++对象。 即使这样,你也可以设计一种(丑陋的,维护密集的)将这种方法用于上述范例,以便通过将它们的名称和参数指定为字符串来调用方法。
要考虑的另一个方面是对象创建 。 要在不知道具体类型的情况下完成此操作,您需要一个工厂函数,以及类的唯一标识符,以指定您想要的具体类。 如C ++专家Herb Sutter所述 ,可以安排类在启动时向全局工厂注册自己 – 这可以避免维护巨大的switch
语句,从而大大简化维护。 可以使用单个工厂,但这意味着系统中的每个对象都必须实现一个接口(工厂将返回指针或对此接口类型的引用)。
在一天结束时,最终结果是(同构) COM – dynamic_cast
执行与QueryInterface(IID_IFoo)
相同的工作,并且所有对象实现的基接口等同于IUnknown
。
由于C ++标准没有涵盖“元数据”这样的概念,因此除了您已经提到的RTTI之外,没有可移植的(跨不同的编译器和平台)运行时reflection方法。
在C ++中,还有编译时reflection的可能性(想想boost::type_traits
和boost::type_of
),但与Nemerle或LISP相比,它也有限。
大多数主要框架(MFC,Qt等)允许您在运行时提取元信息,但它们需要各种特殊注释才能工作(请参阅RUNTIME_CLASS等作为示例)。
看看我对类似问题的回答 。 提出的两种解决方案(XRTTI和OpenC ++)都基于外部工具,这些工具在构建过程中为您生成reflection元数据。
您需要使用访客模式。 任何可以反映的类都需要inheritance一个给它一个Reflect
成员函数的基类,该函数接受一个访问者类。 然后, Reflect
function会将有关其他成员的信息或function传递给访问者。
许多流行的库在特定情况下使用此模式,例如,MFC中的Serialize
函数执行此操作,但专门用于序列化。
您可以设计一个系统,使访问者能够对成员函数进行动态调用,获取或设置数据成员的值等。但是每个类都有责任维护写入的Reflect
函数手工,这将是class级结构的重复。
RTTI是一个解决方案(您认为Java中的哪个部分不在RTTI中?),否则您可以实现自己的对象框架 – 让每个您自己的C ++对象inheritance一些reflection接口,然后它应该工作。
反思是计算机程序可以观察和修改其自身结构和行为的过程。 我不知道如何在C ++中进行reflection。 RTTI仅对运行时内存中对象的数据类型有用。
如果您正在使用它是dependency injection(某些接口的实现^ H ^ H ^ H ^ H ^ H ^纯抽象类),您可以尝试动态加载.dll或.so文件,其中包含实现无论插件是什么的当天。
可能只是抓住稻草,因为这对于同时进行多项实施并不适用。
您需要在C ++中做什么,以及您正在使用什么平台? 我知道一种获取完整类定义并使用此数据调用函数的方法,它适用于Windows,但我不了解其他平台。 想法是从DLL或exe导出表中获取数据。 这并不容易 – 我们花了几个月的时间来完成一个体面的实现 – 但它会完成reflection支持语言所做的一切。