views:

671

answers:

8
+6  Q: 

Reflection in C++

Hi, everyone. This is my very first question in SO. I've been working for years with 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++. So now I'm wondering if there is any Reflection mechanism in C++. I've read about RTTI but I feel it's by no means the power of Java (or other languages) Reflecion. I'm beggining to think that there's no way to do this in C++. Am I wrong?

Thanks a lot!

+1  A: 

RTTI is a solution (what part in Java do you think is not in RTTI?), otherwise you can implement your own object framework - let every your own C++ object inherits some reflection interface, and then it should work.

Francis
I think my knowledge about RTTI is poor...but is there any way of getting a list of methods or attributes of an object using RTTI?
aitor
@aitor: No, i don't believe so. RTTI can tell you the type of an object at runtime, but it is your responsibility to convert this information into more precise ones, such as the availability of methods and attributes.
Benoît
Complex RTTI may look like this: http://www.codeproject.com/KB/library/vcf_rtti.aspx
Francis
@Francis: Interesting link. Allowing an author to use macros inside the class file like that does improve maintainability, but it has to be said that this solution is nowhere near as safe (or pretty) as that in Java, where it's impossible for those macros to get out of sync -- because they never have to exist.
j_random_hacker
That's Borland's VCL specific, not standard C++ RTTI.
Daniel Earwicker
+13  A: 

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.

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.

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).

Anton Gogolev
A: 

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.

Probably just grasping at straws, as this won't work well for multiple implementations of things at the same time.

Roboprog
+2  A: 

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. Then the Reflect function would pass information or capabilities about the other members to the visitor.

Many popular libraries use this pattern for specific cases, for example, the Serialize function in MFC does this but specifically for serialization.

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.

Daniel Earwicker
A: 

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++. RTTI is useful only for object's data type in memory at runtime.

MickTaiwan
+2  A: 

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.

Carl Seleborg
+1  A: 

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:

  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). You can see whether this object supports interface IBar by saying:

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. 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. 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. 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.

j_random_hacker
A: 

What do you need to do in C++, and what platform are you working with? 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. The idea is to take data from the DLL or exe export table. 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.

Roderick