简体   繁体   English

用C ++反思

[英]Reflection in C++

I've been working for years with Java. 我一直在使用Java工作多年。 During those years, I've made extensive (or maybe just frequent) use of reflection, and found it useful and enjoyable. 在那些年里,我已经广泛(或者可能只是经常)使用反射,并发现它有用且令人愉快。 But 8 months ago I changed my job, and now Java is just a memory, and I'm getting my hands on C++. 但是8个月前我改变了我的工作,现在Java只是一个记忆,而我正在接受C ++。 So now I'm wondering if there is any reflection mechanism in C++. 所以现在我想知道C ++中是否有任何反射机制。 I've read about RTTI but I feel it's by no means the power of Java (or other languages) reflecion. 我读过有关RTTI的内容,但我觉得这绝不是Java(或其他语言)反射的强大功能。 I'm beggining to think that there's no way to do this in C++. 我开始认为在C ++中没有办法做到这一点。 Am I wrong? 我错了吗?

Since C++ standard does not cover such concept as "metadata", there's no portable (across different compilers and platforms, for that matter) method of run-time reflection other than RTTI you already mentioned. 由于C ++标准没有涵盖“元数据”这样的概念,因此除了您已经提到的RTTI之外,没有可移植的(跨不同的编译器和平台)运行时反射方法。

In C++, there's also a possibility of compile-time reflection (think boost::type_traits and boost::type_of ), but it's limited as well compared to, say, Nemerle or LISP. 在C ++中,还有编译时反射的可能性(想想boost::type_traitsboost::type_of ),但与Nemerle或LISP相比,它也有限。

Most major frameworks (MFC, Qt, etc.) allow you to extract metainformation at run-time, but they require all kinds of special annotations for it to work (see RUNTIME_CLASS et al as an example). 大多数主要框架(MFC,Qt等)允许您在运行时提取元信息,但它们需要各种特殊注释才能工作(请参阅RUNTIME_CLASS等作为示例)。

If you are looking for a totally general way to manipulate objects at runtime when you don't know their types at compile time in C++, you essentially need to: 如果您正在寻找一种在运行时操作对象的完全通用的方法,当您在C ++编译时不知道它们的类型时,您基本上需要:

  1. Define an interface (abstract base class with all pure virtual methods and no members) for each capability that a class might support. 为类可能支持的每个功能定义一个接口(具有所有纯虚方法的抽象基类,没有成员)。
  2. Each class must inherit virtually from all interfaces that it wants to implement (possibly among other classes). 每个类必须从它想要实现的所有接口(可能在其他类中)中虚拟继承。

Now, suppose pFoo holds an interface pointer of type IFoo* to some object x (you don't need to know x 's concrete type). 现在,假设pFoo将一个类型为IFoo*的接口指针保存到某个对象x (您不需要知道x的具体类型)。 You can see whether this object supports interface IBar by saying: 您可以通过以下方式查看此对象是否支持接口IBar

if (IBar* pBar = dynamic_cast<IBar*>(pFoo)) {
    // Do stuff using pBar here
    pBar->endWorldHunger();
} else {
    // Object doesn't support the interface: degrade gracefully
    pFoo->grinStupidly();
}

This approach assumes you know all relevant interfaces at compile time -- if you don't, you won't be able to use normal C++ syntax for calling methods anyway. 这种方法假设您在编译时了解所有相关接口 - 如果不这样做,您将无法使用普通的C ++语法来调用方法。 But it's hard to imagine a situation where the calling program doesn't know what interfaces it needs -- about the only case I can think of would be if you want to expose C++ objects via an interactive interpreter. 但是很难想象调用程序不知道它需要什么接口的情况 - 关于我能想到的唯一情况是,如果你想通过交互式解释器公开C ++对象。 Even then, you can devise an (ugly, maintenance-intensive) way of shoehorning this into the above paradigm, so that methods can be called by specifying their names and arguments as strings. 即使这样,你也可以设计一种(丑陋的,维护密集的)将这种方式用于上述范例的方法,以便通过将它们的名称和参数指定为字符串来调用方法。

The other aspect to consider is object creation . 要考虑的另一个方面是对象创建 To accomplish this without knowing concrete types, you'll need a factory function, plus unique identifiers for classes to specify which concrete class you want. 要在不知道具体类型的情况下完成此操作,您需要一个工厂函数,以及类的唯一标识符,以指定您想要的具体类。 It's possible to arrange for classes to register themselves with a global factory upon startup, as described here by C++ expert Herb Sutter -- this avoids maintaining a gigantic switch statement, considerably easing maintenance. 如C ++专家Herb Sutter所描述的那样,可以安排类在启动时向全局工厂注册自己 - 这可以避免维护巨大的switch语句,从而大大简化维护。 It's possible to use a single factory, though this implies that there is a single interface that every object in your system must implement (the factory will return a pointer or reference to this interface type). 可以使用单个工厂,但这意味着系统中的每个对象都必须实现一个接口(工厂将返回指针或对此接口类型的引用)。

At the end of the day, what you wind up with is basically (isomorphic to) COM -- dynamic_cast<IFoo*> does the same job as QueryInterface(IID_IFoo) , and the base interface implemented by all objects is equivalent to IUnknown . 在一天结束时,最终结果是(同构) COM - dynamic_cast<IFoo*>执行与QueryInterface(IID_IFoo)相同的工作,并且所有对象实现的基接口等同于IUnknown

Have a look at my answer to a similar question . 看看我对类似问题的回答 Both solutions (XRTTI and OpenC++) proposed are based on external tools that generate the reflection meta-data for you during the build process. 提出的两种解决方案(XRTTI和OpenC ++)都基于外部工具,这些工具在构建过程中为您生成反射元数据。

You need to use the visitor pattern. 您需要使用访客模式。 Any class that can be reflected on would need to inherit a base class that gave it a Reflect member function, which would accept a visitor class. 任何可以反映的类都需要继承一个基类,它给它一个Reflect成员函数,它接受一个访问者类。 Then the Reflect function would pass information or capabilities about the other members to the visitor. 然后, Reflect功能会将有关其他成员的信息或功能传递给访问者。

Many popular libraries use this pattern for specific cases, for example, the Serialize function in MFC does this but specifically for serialization. 许多流行的库在特定情况下使用此模式,例如,MFC中的Serialize函数执行此操作,但专门用于序列化。

You could probably design a system in such a way that the visitor would be able to make dynamic calls to member functions, get or set the values of data members, etc. But it would be the responsibility of each class to maintain a Reflect function written by hand, which would be a repetition of the structure of the class. 您可以设计一个系统,使访问者能够对成员函数进行动态调用,获取或设置数据成员的值等。但是每个类都有责任维护一个Reflect函数的编写手工,这将是班级结构的重复。

RTTI是一个解决方案(您认为Java中的哪个部分不在RTTI中?),否则您可以实现自己的对象框架 - 让每个您自己的C ++对象继承一些反射接口,然后它应该工作。

Reflection is the process by which a computer program can observe and modify its own structure and behavior. 反思是计算机程序可以观察和修改其自身结构和行为的过程。 I don't see how you can do reflection in C++. 我不知道如何在C ++中进行反射。 RTTI is useful only for object's data type in memory at runtime. RTTI仅对运行时内存中对象的数据类型有用。

What do you need to do in C++, and what platform are you working with? 您需要在C ++中做什么,以及您正在使用什么平台? I know of one way to get the complete class definitions and invoke functions using this data, it works in Windows but I don't know about other platforms. 我知道一种获取完整类定义并使用此数据调用函数的方法,它适用于Windows,但我不了解其他平台。 The idea is to take data from the DLL or exe export table. 想法是从DLL或exe导出表中获取数据。 It's not easy - it took us several months work to get a decent implementation - but it will do everything that reflection-supporting languages do. 这并不容易 - 我们需要花费几个月的时间才能获得一个体面的实现 - 但它会完成反射支持语言所做的一切。

if all you are using it for is dependency injection (an implementation of some interface^H^H^H^H^H^ pure abstract class), you might try dynamic loading of .dll or .so files which contain the implementation-of-the-day for whatever the plug in is. 如果您正在使用它是依赖注入(一些接口的实现^ H ^ H ^ H ^ H ^ H ^纯抽象类),您可以尝试动态加载包含实现的实现的.dll或.so文件无论插件是什么的当天。

Probably just grasping at straws, as this won't work well for multiple implementations of things at the same time. 可能只是抓住稻草,因为这不适合同时进行多项实施。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM