用C ++反思

我一直在使用Java工作多年。 在那些年里,我已经广泛(或者可能只是经常)使用reflection,并发现它有用且令人愉快。 但是8个月前我改变了我的工作,现在Java只是一个记忆,而我正在接受C ++。 所以现在我想知道C ++中是否有任何reflection机制。 我读过有关RTTI的内容,但我觉得这绝不是Java(或其他语言)reflection的强大function。 我开始认为在C ++中无法做到这一点。 我错了吗?

如果您正在寻找一种在运行时操作对象的完全通用的方法,当您在C ++编译时不知道它们的类型时,您基本上需要:

  1. 为类可能支持的每个function定义一个接口(具有所有纯虚方法的抽象基类,没有成员)。
  2. 每个类必须从它想要实现的所有接口(可能在其他类中)中虚拟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_traitsboost::type_of ),但与Nemerle或LISP相比,它也有限。

大多数主要框架(MFC,Qt等)允许您在运行时提取元信息,但它们需要各种特殊注释才能工作(请参阅RUNTIME_CLASS等作为示例)。

看看我对类似问题的回答 。 提出的两种解决方案(XRTTI和OpenC ++)都基于外部工具,这些工具在构建过程中为您生成reflection元数据。

您需要使用访客模式。 任何可以反映的类都需要inheritance一个给它一个Reflect成员函数的基类,该函数接受一个访问者类。 然后, Reflectfunction会将有关其他成员的信息或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支持语言所做的一切。