开发者

How would you implement basic reflection in C++?

开发者 https://www.devze.com 2022-12-20 12:42 出处:网络
I\'m thinking about adding some sort of reflection capabilities to some C++ classes ( so that I wouldn\'t have to use RTTI ): getting names of methods, declared fields, class name ... this sort of stu

I'm thinking about adding some sort of reflection capabilities to some C++ classes ( so that I wouldn't have to use RTTI ): getting names of methods, declared fields, class name ... this sort of stuff.

I was thinking about开发者_JAVA百科 parsing existing source files, get a list of declared fields & methods, and rewrite each source file, adding this sort of information to each class.

What do you think about this approach? I'd like to do everything from scratch, since I think it's a great opportunity to learn. Would you suggest other ways of doing this?

//OFFTOPIC: is this how Qt does it?


I would fork gcc.


Check the Boost.Mirror library. It's not been accepted into Boost yet, so you'll have to download it from the Boost Vault.

The library is still in development and the docs are scarce but by studying the provided examples you might be able to achieve what you want.

EDIT: if you really want to parse your own C++ code then maybe you should consider clang


Yes, this is how Qt does it - except it doesn't add the info to the class itself, it creates a new class called a metaclass that contains static data about the class. This is better for obvious reasons.

No pure-C++ approach will provide fully automatic reflection - the language doesn't allow it. There are many attempts, including Boost.Mirror and Boost.Reflection, but they all require boilerplate additions to your source.


Unless you want to modify the C++ compiler or depend on vendor extensions, you will need a heap of CPP macros that build data structures.


You might find gccxml worth a look. It'll (for example) convert this to this, which means you just have to parse XML instead of C++.

There's an interesting SP&E paper which describes using gccxml in conjunction with a modified linker to "provide Java-reflection-like functionality to C++ applications in a clean and non-intrusive manner".


Alter the compiler to produce a static GetClass method, returning a pointer to a Class object describing the class, for every defined class.

Alter the compiler/linker to pull out the metadata needed and stuff those in special sections/symbols of the resulting executable image - much like debugging symbols are added.

GetClass would use (read/load/cache ?) the above metadata.

And yes. That's a lot of work. (And a nice side effect is it's getting you almost halway to eliminating header files - as that info could now be pulled right out of an image)


C++ does not support reflection. The efforts from boost and RTTI are quite limited and half baked. I would not recommend them.

You mentioned that you can start from scatch. Well you can write a C++ lexer using lex/yacc, or ANTLR. Quite a lot of work, but you will learn a lot.

If writing a parser is a formidable task for you, there are some other options to get metadata of a class. Microsoft has DIA SDK that provides symbol information. Doxygen can generate XML files that you can parse to obtain the field names, method names of a class. I had some success parsing doxygen XML files.

If you only work with Microsoft platform, a viable solution is to use type library (TLB). It requires you convert the class into a interface in MS IDL. MIDL compiles the IDL into .tlb, and your application can loads the .tlb file at runtime. Your application can obtain almost all information about the class through ITypeInfo interface, properties and methods.


Follow Greenspun's tenth law and you're good to go: just implement an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp. Pick a half that supports implementing reflection. :)

Or, here's an idea:

Turn on map files (and possibly assembly generation) in your build. Implement an application that generates code to create a dynamic library. You should be able to get all the static information (method names, parameters, types, etc.) about the classes from either the source or one of the build artifacts. Using the map or assembly you should be able to find function addresses, virtual function pointer offsets, global variable addresses, variable offsets, information about stack and register allocated variables, etc. and so forth. From this information build a library containing the calls for getting all this information by passing type names, pointers, function names etc.

Now, in C++, write a library containing functions and macros that allow you to put unique Id's that will be compiled into the code for identifying function starts, all reflection calls, EIP offset upon reflection calls, etc. Use inline assembly macros at appropriate locations that leave room where necessary with NOPs to put a few instructions if you need to, usually right after an ID. Also, provide bridge library functions that will allow the reflection functionality to either handle what it can inline (say getting a function's address) vs. having to make calls out to the dynamic library built in the post-build step.

Finally, write a post-post build reflection linker. I suggest "kniltsoPostlink" but that's up to you. In this step search for your unique IDs (did I mention to make it easy you should probably make the IDs GUIDs so you can search on them in the binary?) and, wherever the ID is marking a reflection call to a function, or a definition of a class, etc., place enough data there (in a format you can easily determine just-in-time as you write the reflector library) and then in the ID before a call to the reflector library, rewrite the call so that it pulls the parameters it needs from those bits of data, or just put the bits of data right there if applicable, I can't really know ahead of time, but as you write it, these little details will just pop out at you.

Anyway, I know I've not given much code, and I actually intend to start a project on this at some point once I have enough spare time. I mean, each little part should be very simple so as you do it incrementally, each little piece should become clear as long as you follow the guidelines laid out here. It's possible that some of it will actually be even simpler than I've described here, because this was a worst-case scenario. You may even get away without ever having to re-write code to the reflector calls at all; just placing the data in the appropriate spots may allow the library to pull those bits as it needs them without further information.

I'm very glad you asked; I'm very busy right now, but if you get a night free, I imagine that will be a good start at a first version, and I'll be happy to pitch in as soon as I can.

;)


Maybe you can use the typeinfo library, with it you can now a object class in runtime. Example:

#include<iostream>

#include<typeinfo>
class A{};

int main()
{
A a;

std::cout<<typeid(a).name();

}

You can see more in: http://www.cplusplus.com/reference/std/typeinfo/

[]`s

0

精彩评论

暂无评论...
验证码 换一张
取 消