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

AGM::LibReflection: A reflection library for C++.

By , 1 Nov 2004
 

Introduction

LibReflection is a little library (well, a header to be specific) that gives reflection capabilities to C++ classes. When we talk about reflection, we don't mean just RTTI, but a rich palette of capabilities useful in every day programming:

  • specify and examine class inheritance
  • declare and examine normal and static fields
  • declare and examine normal, virtual, and static methods
  • declare and use properties and events
  • set and get field values
  • call methods and get results
  • create instances without having the headers at hand, by using a class registry

And all the above almost happen automatically, with very few macros that the programmer has to put in the application's classes...and you also get the added benefit of class properties and events, something that C++ does not provide by default.

Demo

Using LibReflection is very easy. The following piece of code shows a class with fields, properties and methods, all reflected in the class' Class object:

//what you need to include
#include "reflection.hpp"


//namespace usage
using namespace agm::reflection;


//example base class
class Base {
public:
    //needed so as that the class gets reflection capabilities
    CLASS(Base, NullClass);

    //a reflected property
    PROPERTY(int, length);

    //a reflected method
    METHOD(public, bool, processLength, (int l));

private:
    //a reflected field
    FIELD(private, int, m_length);

    //property getter
    int get_length() const {
        return m_length;
    }

    //property setter
    void set_length(int l) {
        m_length = l;
    }
};


//a reflected method implementation
bool Base::processLength(int l)
{
    return l == m_length;
}


//a derived class
class Derived : public Base {
public:
    //derived reflected class
    CLASS(Derived, Base);
};


//for the demo
#include <iostream>
using namespace std;


int main()
{
    //a class instance
    Derived derived;

    //get the class of the Derived class
    const Class &derived_class = derived.getClass();

    //print the class name
    cout << derived_class.getName() << endl;

    //print the the m_length field
    const Field &length_field = derived_class.getField("m_length");
    cout << length_field.getType() << " " 
         << length_field.getName() << endl;

    //print the the length property
    const Property &length_prop = derived_class.getProperty("length");
    cout << length_prop.getType() << " " 
         << length_prop.getName() << endl;

    //print the 'processLength()' method
    const Method &process_length_method = 
                 derived_class.getMethod("processLength");
    cout << process_length_method.getType() << " "
         << process_length_method.getName()
         << process_length_method.getArgs()
         << endl;

    //set the length property
    cout << "using length property" << endl;
    length_prop.set(&derived, 10);
    int i;
    length_prop.get(i, &derived);
    cout << "length = " << i << endl;

    //calling the length method
    cout << "calling bool Base::processLength(int)" << endl;
    bool b;
    process_length_method.invoke(b, (Base *)&derived, 10);
    cout << "processLength=" << b << endl;

    getchar();
    return 0;
}

Documentation

For more information, you can check out my little site here.

License

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

Achilleas Margaritis
Software Developer (Senior)
Greece Greece
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generaltypeless parametersmemberMember 1811246 Oct '08 - 5:26 
Dir Sir,
 
First of all I thank You very much for a great article.
 
I have plan to use this great library in my project but a problem I have with this library is that if I have a property in one object and want to set it into another property in second object then I have to know the type of the property at compile time. Is it possible to somehow get the value of the property without knowing type at compile time.
 
Example:
Foo foo1;
Foo foo2;
 
const Class &foo1_class = foo1.getClass();
const Class &foo2_class = foo2.getClass();
 
const Property &outProp = foo1_class.getProperty("length");
const Property &inProp = foo2_class.getProperty("length");
 
TypeLess value; //This one needs to be somehow be typeless????
outProp.get(value,foo1);
inProp.set(foo2,value);
 

Thanks
/NTN
GeneralWindows CE compilationmemberDuvidaCruel9 Feb '07 - 9:11 
Hi,
 
I'm trying to compile this library int Windows CE, almost everything works, except constructors stuff.
I know that problem is in ARM compiler from EVC because the library compiles fine in Visual Studio.
the part that doesn't work is the following:
 
template
static C *__new_instance_ptr__(void* ptr)
{
return new (ptr) T();
}

template
static C *(* __create_new_instance_ptr__(C *(*)()))(void *)
{
return & __new_instance_ptr__; <-- ERROR C2275
}
 
The error is:
error C2275: 'C' : illegal use of this type as an expression
 
So, i am looking for some workaround for this
 
thanks in advance
GeneralLibReflection for gccsussAnonymous3 May '05 - 4:51 
Hi,
Seems really cool to me.
 
Can someone please post LibReflection h file converted to gcc ?
I am having many problems porting it.
 
Thanks in advance!
QuestionArrays?memberneo26007776 Apr '05 - 9:30 
Have you thought about how field definitions for Arrays would work?
GeneralAn Update Version Postedmembermy203829 Mar '05 - 7:52 
http://www.codeproject.com/useritems/libreflection2.asp[^]
 
Here is my articles of the changes that I have made to the library. It is currently in the "unedited" stage, please vote if you find it useful so that it can get to "edited" stage sooner.

GeneralNew Changes Made to LibReflectionmembermy203823 Mar '05 - 10:22 
Okay, here are the things that I added to your LibReflection library:
 
(1) Constructor information is now captured. You can actually invoke a constructor -- it will automatic create an object using the new operator. And the newInstance() method on the class will automatically called default constructor if one is defined.
 
(2) Method args type and list. Method, Static method and Constructor parameter and return type (std::type_info) can be retrieved.
 
(3) Class Method, Static Method, Constructor can be overloaded. But the MACRO to defined them wasn't as nice.
 
(4) port to gcc. Well, I only use gcc, so that is the only choice.
 
(5) added class registary to lookup or listing of all known classes
 
(6) When invoking a method object with type mismatched, the exception threw will include detailed information about which parameter/ret/object ref are mismatched. This should greater improve the ability to fix it.
 
(7) Full class name (including namespace) are now captured and returned.
 
(8) NEW! NEW! Automatic casting of object class are now working. If your method like a Base * but you pass in a Dervied *, it will automatic cast to the Base *. Also you can cast any class * cast to void *. This will allow alot of code to work in a generic way. Requirement is that both Base & Dervied must be defined in the reflection. This works in reference as well (i.e. Derviced & to Base &) . For example, if your method is defined in class Dervied as
 
Dervied * createThis(Base * b);
 
You can invoke it using:
 
Base *result_ptr;
Dervied d;
 
d.getClass().getMethod("createThis").invoke(result_ptr, &d, &d);
 

(9) NEW! NEW! NEW! Dynamic pointer casting are now working. The known object pointer will automatic test for dynamic castable to its dervied type. This allow you to invoke method using Base class pointer. For the sample above, we can invoke it as:
 
Base *p = &d;
d.getClass().getMethod("createThis").invoke(result_ptr, p, &d);
 
(10) Work in template class as well.
 
Limitation (same as original) :
An instance of the class must be created before the class is "known".
 
Single inhertiance only. 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
 
Let me know if there is a way I can send you back the changes...

GeneralRe: New Changes Made to LibReflectionmemberWREY28 Mar '05 - 0:14 
Your changes sound very interesting!
 
Why don't you write an article about it and make reference that it's an extension (in a sort of way) to AGM::LibReflection. That way, you can show your changes as well as the other author's code.
 
I am currently doing something like this, and would very much like to see the changes to which you are referring.
 
Big Grin | :-D
 
William
 
Fortes in fide et opere!
GeneralRe: New Changes Made to LibReflectionmembermy203828 Mar '05 - 6:40 
I could but ...
 
(1) The changes is based on axilmar's work. I don't want look as if I am looking for ways to claim credit for his work. But on the other hand, I don't think he is reading this site anymore as someone else is also looking for his help.
 
(2) The code works in gcc. But I have not tested them in VC and I notice this is a MSVC/.net site, so it would probably made sense for someone to compile the code in MSVC first.
 

GeneralNot totally true.memberWREY28 Mar '05 - 8:23 
Some of the things you say make sense, but if you were to write an article it would be YOUR article and you wouldn't be infringing on anybody else's work especially if in your article you make it clear that your work is to be considered an extension of the other author's previous submission. Your article will essentially be containing NEW work. So where is the infringement?
 
Besides, in your article (if it'd make you feel more comfortable), you can clearly give the other author credit for planting the seeds of ideas in your head for what you have submitted.
 
I personally don't see any conflict of anything.
 
With regards to this being a ".net" site, you must be fairly new, because there are (literally) thousands upon thousands of non-".net" materials here.
 
It simply boils down to this, "Where there's a will, there's a way!!"
 
Suspicious | :suss:
 
William
 
Fortes in fide et opere!
GeneralRe: Not totally true.membermy203829 Mar '05 - 7:53 
Okay, here we go: http://www.codeproject.com/useritems/libreflection2.asp[^]
GeneralCompile Error in VS.NET 1.1membercolormegjian22 Mar '05 - 3:26 
I just compiled the source code posted on the page in VS.NET 1.1,but found
 
error C2039: “Base” : is not member of “Base::__method_processLength__”
which refers to "METHOD(public, bool, processLength, (int l));"
 
who could help me? thanks in advance!
GeneralRe: Compile Error in VS.NET 1.1membertomthorne22 Apr '05 - 7:23 
I'm getting the same errors... any clues anyone?
GeneralRe: Compile Error in VS.NET 1.1memberderchoff6 Oct '05 - 0:15 
Same problem for me. But it works with VS.NET 2005 !
 
http://www.codeproject.com/library/libreflection2.asp?msg=1246303#xx1246303xx
[^]
-- modified at 6:15 Thursday 6th October, 2005
QuestionCan i use it in BCB?memberFlameBlade17 Feb '05 - 2:41 
i just wanna use this in bcb.But there is something wronge with it.how can i?thanks!
GeneralContactsusspsyclonist (Stephan K.)22 Nov '04 - 1:41 
Very interesting library. We are working on a reflection library for a few months (includes more than one rewrite Wink | ;) ). We've given your library a try and added quite a few things. We'd like to contact you in order to talk with you about possible uses, modifications, addons etc if you're interested. We sent you e-mails to at least two different e-mail adresses but they probably didn't reach you.
 
How can we contact you?
 
Cheers!
QuestionCan Instance be Created Dynamicly?memberLaisser21 Nov '04 - 6:21 
Can instance of the class be Created dynamicly?
Like the the CreateObject() function of CRuntimeClass in MFC Or the Activator.CreateInstance Method in .NET
GeneralVery Interesting!memberggerules10 Nov '04 - 5:19 
Good work. Thanks!
GeneralCool!memberJim Crafton2 Nov '04 - 14:15 
Nice job - I came up with a similar approach to your, check it out here: http://vcf.sourceforge.net[^].
VCF::Class[^] will give you taste of what it does.
 
Any success with other compilers? GCC, Borland, or DigitalMars?
 
Again, congrats on the nice work!

 
¡El diablo está en mis pantalones! ¡Mire, mire!
 
Real Mentats use only 100% pure, unfooled around with Sapho Juice(tm)!
 
SELECT * FROM User WHERE Clue > 0
0 rows returned

GeneralRe: Cool!memberaxilmar3 Nov '04 - 2:37 
You did a nice job too. Generally, our thinking is on the same line, but we have differences in the implementation.
 
I've solved an issue with some macros and now my code works for GCC also. But I haven't finished yet, there are lots of features still pending.
 
Watch this space for further developements!
GeneralRe: Cool!membermy203815 Mar '05 - 10:27 
mmm, If you have ported it to gcc, why don't you post it... I spend the last few hours doing that and were just done.
GeneralDudememberarmentage2 Nov '04 - 9:23 
If you plan on writing C++ that looks like this, you seriously need to discover C++/CLR, C#, and Java, and stick with them.

GeneralRe: Dudememberaxilmar2 Nov '04 - 9:42 
Ehm...why do you say that?

GeneralRe: DudememberDave Handley3 Nov '04 - 6:10 
Unfortunately, there are lots of reasons for NOT using the CLR, be it with Managed C++ or C# (and also for not using Java) - but in those cases Reflection can still be very useful.
 
Some of the reasons why I haven't been able to use Managed C++ or C# (despite incentive to try) include:
 
1) Immature libraries. Because the languages haven't been around very long, the libraries have a huge number of weaknesses - the last time I tried to use C# I found that I couldn't create a directory browser from the file dialog since the file dialog didn't include that feature and it was a final class. In C++ I would simply inherit off CFileDialog.
 
2) The syntax is impenetrable. Managed C++ has improved slightly with the newer work Microsoft has done, but it is still nowhere near as clear as well written C++.
 
3) The syntax is non-standard. Except in the rare cases where the CLR exists for other platforms and compilers, you are stuck with VC++ and Windows.
 
4) The CLR is incredibly slow compared to raw C++. Because you are working through an intermediate language, and you have the overhead of garbage collection and smart pointers, for time critical applications Managed C++ just doesn't hold up. I write CAD applications for a living and Managed C++ just wouldn't cut it.
 
5) It is very difficult to use Managed and Unmanaged code side by side. Again, last time I checked, ALL your code had to be recompiled with the compiler switch for CLR included. That scares me because calls from unmanaged code into managed code are going to have loads on non-deterministic wrappers around them.
 
I'll get off my soapbox now - but suffice it to say that I haven't been impressed with the CLR - and it certainly doesn't remove the need to provide decent reflection libraries under certain circumstances in C++.
 
Good work on AGM::LibReflection.
 
Dave
GeneralRe: DudememberAnders Dalvander13 Nov '04 - 2:03 
Dave Handley wrote:
1) Immature libraries. Because the languages haven't been around very long, the libraries have a huge number of weaknesses - the last time I tried to use C# I found that I couldn't create a directory browser from the file dialog since the file dialog didn't include that feature and it was a final class. In C++ I would simply inherit off CFileDialog.
 
CFileDialog isn't really standard C++, it is a MFC class, and thus will only work in Microsoft Windows. But should't you use the Win32 function SHBrowseForFolder, and not derive from CFileDialog anyway?
 
Dave Handley wrote:
2) The syntax is impenetrable. Managed C++ has improved slightly with the newer work Microsoft has done, but it is still nowhere near as clear as well written C++.
 
True, Managed C++ wasn't very neat to use, and that is why C++/CLI[^] was developed. C++/CLI is as penetrable as standard C++, atleast when you are doing the same thing. I wouldn't state that standard C++ is clear, either.
 
Dave Handley wrote:
3) The syntax is non-standard. Except in the rare cases where the CLR exists for other platforms and compilers, you are stuck with VC++ and Windows.
 
The CLR, CLI, C# and C++/CLI are standards, but you're stuck in .NET, that is true. But .NET is ported to other systems than Windows. See DotGnu[^] and Mono[^].
 
Dave Handley wrote:
4) The CLR is incredibly slow compared to raw C++. Because you are working through an intermediate language, and you have the overhead of garbage collection and smart pointers, for time critical applications Managed C++ just doesn't hold up. I write CAD applications for a living and Managed C++ just wouldn't cut it.
 
You are not working through an intermediate language, the JIT-compiler will create machine code. In C++/CLI you don't have to use garbage collection, you can use deterministic destruction instead.
Vertigo Software ported Quake 2[^] to .NET with a performance decrease of only 15%. And that was done in 5 days: 4 days for porting from C to C++ and one day to port to Managed C++.
GeneralRe: DudememberDave Handley13 Nov '04 - 3:08 
"CFileDialog isn't really standard C++, it is a MFC class, and thus will only work in Microsoft Windows. But should't you use the Win32 function SHBrowseForFolder, and not derive from CFileDialog anyway?"
 
Unfortunately, even using SHBrowseForFolder isn't trivial in the .Net Framework - see http://www.netomatix.com/FolderBrowser.aspx
 
"I wouldn't state that standard C++ is clear, either."
 
ANSI Standard C++ is very clear in my opinion - much more so than many other languages. Especially given the amount of explicit control you have over data management.
 
"The CLR, CLI, C# and C++/CLI are standards, but you're stuck in .NET, that is true. But .NET is ported to other systems than Windows. See DotGnu and Mono."
 
C++/CLI is a standard but it still is NOT ANSI Standard C++ which makes it much less portable. .Net may be ported to a few other platforms, but it still isn't properly cross-platform.
 
"You are not working through an intermediate language, the JIT-compiler will create machine code. In C++/CLI you don't have to use garbage collection, you can use deterministic destruction instead."
 
As far as I know the only way to do deterministic destruction is with the IDisposable interface, and even then the Garbage Collector does some of the work so it isn't strictly fully deterministic. Also any form of Just in Time Compiler directly implies the existence of intermediate code - of course the IL is converted to machine code before it is used, but it is still converted and that takes time.
 
"Vertigo Software ported Quake 2 to .NET with a performance decrease of only 15%. And that was done in 5 days: 4 days for porting from C to C++ and one day to port to Managed C++."
 
Unfortunately, something like Quake 2 isn't really a good example of a performance intensive application. From what I remember Quake 2 was written to run on a Pentium 133, and as with many games most of the really performance intensive stuff is done inside the OpenGL library down on the Graphics Card. That will still be the same in a managed port. When someone gets a ray-tracer working in managed code with similar performance to native C++ I'll be impressed, but I can't see it happening. Given that most of the really intensive stuff in Quake 2 is happening down on the graphics card, a 15% performance drop is huge.
 
Dave

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 2 Nov 2004
Article Copyright 2004 by Achilleas Margaritis
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid