Click here to Skip to main content
Click here to Skip to main content

An update to AGM::LibReflection: A reflection library for C++

, 11 May 2005
Rate this:
Please Sign up or sign in to vote.
This article is an update to the original AGM::LibReflection library.


The original LibReflection written by axilmar has quite a few of the limitations that has been improved or relaxed in this version. This article will only describe the differences between the original and the new version. All of the existing functionalities and syntax are still supported and will work in the new version. Therefore, upgrade to a new version should be as simple as re-compiling the code. Reader should read the original LibReflection article before continuing.

The following items are changed/improved on the new version:

  1. Constructor information is now captured and stored within the Class object. Additionally, constructor can be invoked to create an object via the new operator. When a default constructor is reflective into the Class, the Class::newInstance() method can be used as a shortcut to creating an instance. Example:
    using namespace agm::reflection;
    using namespace std;
    class Widget
        CLASS(Widget, NullClass);
        CONSTRUCTOR(public, Widget, ())
        cout << "default constructor called" << endl;
        CONSTRUCTOR(public, Widget, (int y) )
        cout << "Widget(int) called with " << y << endl;
    int main()
        Widget w;
        const Class & cls = w.getClass();
        Widget* wp = static_cast<Widget*>( cls.newInstance() );
        delete wp;
  2. In the original version, method argument type and return type are not captured. This has been changed. User can now retrieve type information (in the form of std::type_info) of the method argument and return. Using the class definition of Widget above:
        const Class::ConstructorList & constructors = cls.getConstructors();
        for (Class::ConstructorList::const_iterator iter = constructors.begin();
             iter != constructors.end();
            const ConstructorMethod& cm = *iter;
            // we will look for Widget(int) constructor
            if (cm.getArgsCount() == 1 && *cm.getArgsTypes()[0] == typeid(int))
            cout << "Found Widget(int) constructor" << endl;
            Widget *wp2;
            cm.invoke(wp2, 12);
            delete wp2;
  3. Class methods, static methods and constructors can be overloaded. User can search and iterate through all of the overloaded methods to select the one they are looking for. This is usually done by examining the argument type and returning the type of the method candidates. Example of overloading a constructor is already shown above. Static methods and class methods are defined similarly. Use of different macros is no longer required.
  4. Added simple Class registry. This allows users to list or search through the entire collection of "known" classes. Using the Widget example above:
        const Class * wcls = Class::forName("Widget");
        if (wcls != 0)
        cout << "Calling newInstance()" << endl;
        Widget* wp = static_cast<Widget*>( wcls->newInstance() );
  5. Improved description on TypeMismatchError. When a method (whether it is a constructor, static method or class member method) is invoked with an incompatible type, the exception thrown will contain detailed information regarding which parameter is incompatible. Here is an example of a TypeMismatchError exception thrown:
    terminate called after throwing an instance of 
     what():  static Label* Label::self(Label*):
    (WARN only: type castable)return type mismatched: expected 
                                     (Label*) passed (Widget*);
    Parameter 1 mismatched: expected (Label*) passed (Widget*);
  6. Full class name (including namespace) is now captured and can be queried via Class::getFullName(). Similarly, the method (constructor, static, member) now contains a new method getSignature() which returns human readable class and argument type.
  7. Automatic casting of object class for compatible pointer and reference types. For example, if a method (constructor, static, member) takes a Base *, but a Derived * is passed as the argument, the Derived * will be automatically cast to Base *. The original version will simply throw the TypeMismatchError exception when the argument is not of exact type. This works for return values as well. The requirement is that both Base and Derived must be defined using reflection.
    class Label : public Widget
        CLASS(Label, Widget);
        CONSTRUCTOR(public, Label, ())
        cout << "Label:: default constructor called" << endl;
        STATIC_METHOD(public, Label *, self, (Label *that) )
        cout << "The object type is " << that->getClass().getFullName() << endl;
        return that;
    int main()
        Label l;
        Widget* wp = &l;
        Widget* wp_result;
        l.getClass().getStaticMethod("self").invoke(wp_result, &l);
        /* wp_result pointer to a Label * object */

    In this example, self() is returning a Label * but the result object passed is a Widget *. The returning pointer is automatically cast.

  8. Dynamic type casting to its object class (down casting) for compatible pointer type. When a method expects a Derived * but the argument passed is a Base *, the reflection library will attempt to cast the Base * to Derived * via the dynamic_cast<> C++ operator. If the cast is not successful, TypeMismatchError exception is thrown; otherwise the invocation will take place. Using the previous example:
        l.getClass().getStaticMethod("self").invoke(wp_result, wp);
        /* wp is of type Widget *, but the argument requires a Label * */
  9. The LibReflection library now works in template classes as well. Templated method functions, however, can not be reflective. This is extracted from the example code in the template.cpp file:
    template <class T> class Widget
        CLASS(Widget, NullClass);
        CONSTRUCTOR(public, Widget, ())
        : storage()
        cout << "default constructor called" << endl;
        CONSTRUCTOR(public, Widget, (const Widget& x) )
        : storage(
        cout << "copy constructor called" << endl;
        CONSTRUCTOR(public, Widget, (const T& y) )
        : storage(y)
        cout << "Widget(T) called with " << y << endl;
        METHOD(public, void, store, (T x))
        cout << "calling store with " << x << endl;
        this->storage = x;
        virtual ~Widget() {}
        T storage;
    template <class X, class Y> class Label : public Widget<X>
        CLASS(Label, Widget<X>);
        CONSTRUCTOR(public, Label, ())
        : Widget<X>(), y_store()
        cout << "default constructor called" << endl;
        CONSTRUCTOR(public, Label, (const Label& x) )
        : Widget<X>(x), y_store(x.y_store)
        cout << "copy constructor called" << endl;
        CONSTRUCTOR(public, Label, (const X & x, const Y & y) )
        : Widget<X>(x), y_store(y)
        cout << "Label(x,y) called with " << y << endl;
        METHOD(public, void, store2nd, (Y y))
        cout << "calling store2nd with " << y << endl;
        y_store = y;
        Y y_store;
  10. Added support for dynamic reflection without MACRO. Any public class can be added to the LibReflection using the template class ReflectiveClass. The resulting class defined in LibReflection is identical to the class added using the MACRO method. This method of reflection is suitable for any class for which modification of class definition is impossible (such as vendor library). Using our beloved Widget / Label example, here is the same code defined using dynamic reflection:
    class Label : public Widget
        cout << "Label:: default constructor called" << endl;
        static Label * self (Label *that) 
        cout << "The object type is " << that->getClass().getFullName() << endl;
        return that;
    // dynamic class reflection to LibReflection
    static const ReflectiveClass<Label> label_clsdef = 
        .static_method(&Label::self, "self");

    The one minor difference is that because the class was un-modified, the getClass() and getStaticClass() are no longer part of the Label class. The agm::reflection::Class * can be retrieved by either label_clsdef.get() or using the Class registry Class::forType(const std::type_info&) static member function.

  11. Added custom user defined macro. User can define macro REFLECTION_TYPE_CUSTOMx where x is 1 to 4 before including the reflection header file. If defined, the macro should evaluate to a const std::type_info& object. The custom type macro is useful if user must be able to lookup a particular class within a templated class. For instance, using smart pointer from boost library, we can have the following: #define REFLECTION_TYPE_CUSTOM1(C) typeid(boost::shared_ptr<C>). We can then test the corresponding type by using the Class::findType(const std::type_info& t). It is particularly useful when the exact type of the parameter is not known.
  12. Added support for placement instantiation (also known as placement new). The ConstructorMethod can be invoked using either invoke() or invokePlacement() which takes an extra void * for placement of the object.
  13. Ported to GCC. This can be seen as a non-improvement as the new version has not been tested under MSVC or VS.NET.

Limitation (same as original):

  • An instance of the class must be created before the class is "known".
  • Single inheritance only and no virtual base class.
  • Some of the implicit conversion originally done by the compiler will not be performed. E.g.: long -> int, const char * -> string, etc.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author


United States United States
No Biography provided

Comments and Discussions

Bugerror when parameter of method(static or not), is modified by "const &" Pinmemberangelfish198920-Nov-13 15:23 
QuestionUsing AGM::LibReflection in a DLL [modified] Pinmemberjpvanoosten23-Nov-09 23:09 
AnswerRe: Using AGM::LibReflection in a DLL PinmemberMartial Spirit15-Nov-10 0:04 
GeneralAttributes (or Annotations) on reflective classes. Pinmemberjpvanoosten14-Dec-08 23:57 
GeneralGetting a class without knowing a type. Pinmemberjeremiah300010-Dec-08 12:41 
GeneralRe: Getting a class without knowing a type. Pinmemberjeremiah300010-Dec-08 12:44 
GeneralRe: Getting a class without knowing a type. Pinmemberjeremiah300010-Dec-08 12:53 
GeneralRe: Getting a class without knowing a type. Pinmembermy203821-Sep-09 11:14 
QuestionHow can I use ReflectiveClass::constructor()? Pinmemberyoonjae8-Jul-07 19:21 
AnswerRe: How can I use ReflectiveClass::constructor()? Pinmembermy203810-Jul-07 4:25 
GeneralWinCE compilation PinmemberDuvidaCruel9-Feb-07 9:12 
GeneralDoesn't link correctly Pinmembermpreddie196424-Mar-06 2:39 
GeneralRe: Doesn't link correctly Pinmemberjeremiah300010-Dec-08 10:00 
Generalit doesn't compile with VS.NET 2003 Pinmemberderchoff5-Oct-05 21:50 
GeneralRe: it doesn't compile with VS.NET 2003 Pinmemberyangyunzhao7-Jul-09 16:24 
GeneralSource updated Pinmembermy20384-May-05 3:30 
Generaldynamic class reflection without MACRO Pinmembermy20385-May-05 11:49 
GeneralRe: dynamic class reflection without MACRO Pinmemberpsyclonist11-May-05 21:10 
GeneralRe: dynamic class reflection without MACRO Pinmembermy203812-May-05 9:53 
GeneralRe: dynamic class reflection without MACRO Pinmembermy203820-May-05 4:06 
Generalgcc makefile PinsussAnonymous3-May-05 5:06 
GeneralRe: gcc makefile Pinmembermy20383-May-05 5:18 
GeneralRe: gcc makefile PinsussAnonymous3-May-05 21:01 
GeneralRe: gcc makefile PinsussAnonymous3-May-05 21:14 
GeneralRe: gcc makefile Pinmembermy20384-May-05 3:41 
Generalgee... PinmemberTutu29-Mar-05 19:15 
GeneralRe: gee... PinmemberLivid30-Mar-05 18:37 
GeneralRe: gee... Pinmembermy203831-Mar-05 4:36 
GeneralRe: gee... PinmemberLivid4-Apr-05 21:08 
GeneralRe: gee... Pinmembermy20385-Apr-05 4:55 
Livid, you created quite a bit of code that may indeed serve your purpose. But, however, you can simply define REGISTERCLASSTYPE macro as
#define REGISTERCLASSTYPE(ClassName) static void * __XXX_##ClassName = delete ( new ClassName() );
I thought of somethings similiar; but I actually do not like this solution for serveral reasons
(1) It makes assumption that there is a default constructor, it is available and that the constructor is public and callable. And the class is not an abstract base class.
(2) Same assumption about the destructor
(3) The extra code will make template class invalid. Yes, there is a way to solve it; but your current implementation is not yet there.
(4) It requires the developer to put an extra declaration outside the class definition. If this would have been a requirement that the developer can live with, the developer can simply just define a static instance:
const ClassName my_class_instance;
and that serve the same purpose as well...
Regarding defining multiple base class using ADDBASECLASS macro... Yes, you can indeed capture the information, but its usage is limited in term of what the reflection library can do. One of the reason that why we insist the requirement of single non-virtual inhertiance is that we want to make sure that for any Derived *p, the following is true: p == static_cast<Base *> (p). It makes casting to and from Base class simple. Yes, we can still retrofit our reflection library to work in a limited way. For example, if a Method is defined in the base class and you intended to invoke it, the reflection library need to adjust the Derived *. The situation becomes a little complex when you are invoking a virtual function that may or may not being overriden in the Derived class. The usage is limited in the way that automatic casting (whether implicit or down casting) will not work for parameter type. This limitation is due to we have no way of knowing if a particular parameter is a pointer or reference type ahead of time and therefore, it is impossible to implement the templated invoke() methods. Beside, you can re-assign a referrence type parameter anyway. The question is really how often the multiple base classes is really needed. And can you live with the fact that the second base class will have limited behavior compare to first base class. In any case, yes, we can certainly captures that multiple base classes... but is it worth it?
Regarding your proposed MACRO BEGINCLASSDEF and ENDCLASSDEF, yes it will help to group all of the definition together, but it also restrict the programmer from providing an inline defintion of the method inside the class declaration. I am just guessing at this point because I have not seen how you plan to implement that. You have a good point about the need to group all of the reflective constructor/method/field together. This is due to the way that the LibReflective library insert nested empty class element within the class declaration. Because the compiler are require to allocate at least 1 bytes for any structure (even if there is no data member), the class size can become fairly large if you mix reflective declaration and field. I should probably state this as a guideline in the article.
GeneralRe: gee... Pinmemberliquidy5-Apr-05 6:28 
GeneralRe: gee... Pinmembermy20385-Apr-05 7:24 
GeneralRe: gee... Pinmemberpinturic19-Apr-05 13:42 
GeneralRe: gee... Pinmembermy203822-Apr-05 3:19 
GeneralRe: gee... Pinmemberpinturic25-Apr-05 5:58 
GeneralRe: gee... Pinmembermy203825-Apr-05 7:27 
GeneralRe: gee... Pinmemberpinturic25-Apr-05 7:43 
GeneralRe: gee... Pinmembermy203825-Apr-05 8:01 
GeneralRe: gee... Pinmemberpinturic25-Apr-05 9:32 
GeneralRe: gee... Pinmembermy203825-Apr-05 10:24 
GeneralRe: gee... Pinmemberpinturic25-Apr-05 10:43 
GeneralRe: gee... PinmemberTutu3-May-05 18:16 
GeneralRe: gee... Pinmemberpinturic3-May-05 20:59 
GeneralRe: gee... Pinmembermy20384-May-05 3:31 
GeneralC libreflection gcc Pinmembertunettnt26-Jan-07 8:32 
Generalgcc makefile PinsussAnonymous3-May-05 5:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141022.2 | Last Updated 12 May 2005
Article Copyright 2005 by my2038
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid