Click here to Skip to main content
13,345,867 members (52,757 online)
Click here to Skip to main content
Add your own
alternative version


31 bookmarked
Posted 28 Mar 2005

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 <CODE lang=c++>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.: <CODE lang=c++>long -> <CODE lang=c++>int, <CODE lang=c++>const char * -> <CODE lang=c++>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

You may also be interested in...


Comments and Discussions

Bugerror when parameter of method(static or not), is modified by "const &" Pin
angelfish198920-Nov-13 16:23
memberangelfish198920-Nov-13 16:23 
QuestionUsing AGM::LibReflection in a DLL [modified] Pin
jpvanoosten24-Nov-09 0:09
memberjpvanoosten24-Nov-09 0:09 
AnswerRe: Using AGM::LibReflection in a DLL Pin
Martial Spirit15-Nov-10 1:04
memberMartial Spirit15-Nov-10 1:04 
GeneralAttributes (or Annotations) on reflective classes. Pin
jpvanoosten15-Dec-08 0:57
memberjpvanoosten15-Dec-08 0:57 
GeneralGetting a class without knowing a type. Pin
jeremiah300010-Dec-08 13:41
memberjeremiah300010-Dec-08 13:41 
GeneralRe: Getting a class without knowing a type. Pin
jeremiah300010-Dec-08 13:44
memberjeremiah300010-Dec-08 13:44 
GeneralRe: Getting a class without knowing a type. Pin
jeremiah300010-Dec-08 13:53
memberjeremiah300010-Dec-08 13:53 
GeneralRe: Getting a class without knowing a type. Pin
my203821-Sep-09 12:14
membermy203821-Sep-09 12:14 
QuestionHow can I use ReflectiveClass::constructor()? Pin
yoonjae8-Jul-07 20:21
memberyoonjae8-Jul-07 20:21 
AnswerRe: How can I use ReflectiveClass::constructor()? Pin
my203810-Jul-07 5:25
membermy203810-Jul-07 5:25 
Because there is no way we can get a method pointer to a constructor, we will use a "Type Wrapper" to denote the type you are specifying. As usual, you can specify up to 20 parameters. For example, the class

class Widget {<br />
public:<br />
  Widget() {};<br />
  Widget(int x, int y):m_x(x), m_y(y) {}<br />
  Widget(int x, int y, int width, int height): m_x(x), m_y(y), m_width(width), m_height(height) {}<br />
  Widget(const Widget& that): m_x(that.m_x), m_y(that.m_y), m_width(that.m_width), m_height(that.m_height)<br />
                                , m_visible(that.m_visible), m_enabled(that.m_enabled) {}<br />
  virtual ~Widget(){};<br />

the constructor should be defined as:

<br />
const ReflectiveClass<Widget> clsdef = ReflectiveClass<Widget>()<br />
  .constructor()<br />
  .constructor(Type2Type<int>(), Type2Type<int>())<br />
  .constructor(Type2Type<int>(), Type2Type<int>(), Type2Type<int>(), Type2Type<int>())<br />
  .constructor(Type2Type<const Widget&>())<br />
;<br />

GeneralWinCE compilation Pin
DuvidaCruel9-Feb-07 10:12
memberDuvidaCruel9-Feb-07 10:12 
GeneralDoesn't link correctly Pin
mpreddie196424-Mar-06 3:39
membermpreddie196424-Mar-06 3:39 
GeneralRe: Doesn't link correctly Pin
jeremiah300010-Dec-08 11:00
memberjeremiah300010-Dec-08 11:00 
Generalit doesn't compile with VS.NET 2003 Pin
derchoff5-Oct-05 22:50
memberderchoff5-Oct-05 22:50 
GeneralRe: it doesn't compile with VS.NET 2003 Pin
yangyunzhao7-Jul-09 17:24
memberyangyunzhao7-Jul-09 17:24 
GeneralSource updated Pin
my20384-May-05 4:30
membermy20384-May-05 4:30 
Generaldynamic class reflection without MACRO Pin
my20385-May-05 12:49
membermy20385-May-05 12:49 
GeneralRe: dynamic class reflection without MACRO Pin
psyclonist11-May-05 22:10
memberpsyclonist11-May-05 22:10 
GeneralRe: dynamic class reflection without MACRO Pin
my203812-May-05 10:53
membermy203812-May-05 10:53 
GeneralRe: dynamic class reflection without MACRO Pin
my203820-May-05 5:06
membermy203820-May-05 5:06 
Generalgcc makefile Pin
Anonymous3-May-05 6:06
sussAnonymous3-May-05 6:06 
GeneralRe: gcc makefile Pin
my20383-May-05 6:18
membermy20383-May-05 6:18 
GeneralRe: gcc makefile Pin
Anonymous3-May-05 22:01
sussAnonymous3-May-05 22:01 
GeneralRe: gcc makefile Pin
Anonymous3-May-05 22:14
sussAnonymous3-May-05 22:14 
GeneralRe: gcc makefile Pin
my20384-May-05 4:41
membermy20384-May-05 4:41 

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

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

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.180111.1 | Last Updated 12 May 2005
Article Copyright 2005 by my2038
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid