⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 reflect.html

📁 java 反射机制详解示例,实现类属性及方法修改
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<HTML>
<HEAD>
<TITLE>Reflection for C++</TITLE>
<UL>
<LI> <A HREF = "#introduction">Introduction</A></LI>
<LI> <A HREF = "#architecture">Architecture</A></LI>
<LI> <A HREF = "#limitations">Limitations</A></LI>
<LI> <A HREF = "#usage">Usage</A></LI>
<LI> <A HREF = "#distribution">Distribution</A></LI>
</UL>
<BODY>
<HR>
<H2><A NAME = "introduction">Introduction</A></H2>

Reflection is a mechanism making it possible to investigate yourself.
If we are speaking about programming languages, reflection is used
to investigate format of objects at runtime, invoke methods and access fields
of these objects. Reflection is required if you want to implement some generic code
which can work with objects of unknown (at the time of creation of this code) types.
There are several tasks in which reflection can be used: 
remote method invocation, serialization, object dumps, database interfaces.
How it works? Given some object we first should ask for its <code>type</code>.
As a result we are given class descriptor, which provides information about class methods and
fields. We can use these field descriptors to fetch/store object fields and can use 
method descriptors to lookup and invoke methods.<P>

Many programming languages provide built-in reflection mechanism. For example, in Java
there is special package <code>java.lang.reflect</code> . But unfortunately C++
doesn't support reflection. Not so long ago first step was made in this direction - 
RTTI support was added to the language. But RTTI provides only very restricted subset of reflection:
it allows to get object compile-time and runtime type (it is possible to get object runtime type 
only if object class contains virtual functions). You can compare types and you can get type name -
and that is all you can do with RTTI.<P>

There are several ways of extracting type information for C++:<P>

<TABLE BORDER>
<TR><TH>Approach</TH><TH>Advantages</TH><TH>Disadvantages</TH></TR>
<TR><TD>Parse debugging information</TD>
<TD><UL><LI>Program should not be changed 
<LI>It is possible to extract complete information about types used in the programs</UL></TD>
<TD><UL><LI>Program was build with enabled debugging support and distributed with debugging
information
<LI>There are a lot of different formats of storing debug information, while there are some
standards for formats of executable files (COFF, ELF,...) format of debugging information
usually is more or less specific to the particular compiler</UL></TD></TR>


<TR><TD>Special preprocessor which will parse C++ sources and build class descriptors</TD>
<TD><UL><LI>Program should not be changed</UL></TD>
<TD><UL><LI>Alignment and offset of fields in classes, as well as virtual function table format
and naming conventions are specific to each compiler, so it is not possible to create generic
preprocessor which will produce type information directly. Instead of it, it should generate some 
C++ code, which should be later processed by normal C++ compiler. So build procedure
becomes too complex. 
<LI>Parsing of C++ code is not trivial task. Also to be able to modify preprocessed code, 
this tool should fully handle standard C++ preprocessor directives and has to be 
called with the same options as normal compiler. 
</UL></TD></TR>

<TR><TD>Create specialized compiler which will support reflection</TD>
<TD><UL><LI>This is most convenient case for the user - no extra steps during 
build are required to produce runtime type information.
<LI>Compiler can generate efficient code for reflection methods
</UL></TD>
<TD>
<UL><LI>Creating one's own C++ compiler is a very challenging task.
<LI>Users will still prefer to use their own favorite tools (Visual C++, Borland,...).
It is mostly because most of the modern compilers are not only compilers but IDE with
builtin editor, debugger, profiler, wizards, class libraries....
</UL></TD></TR>

<TD>Let programmer to provide this information himself</TD>
<TD><UL><LI>This is the most portable approach which can be used with any C++ compiler
<LI>This approach is the simplest to implement
<LI>With this approach it is possible to include additional type information
(user defined attributes, for example <I>transient<I>)
</TD>
<TD><UL><LI>Program has to be changed
<LI>Programmer has to do more work
<LI>There is a chance for programmer to make a mistake describing class format
</UL></TD></TR>
</TABLE><P>

<H2><A NAME = "architecture">Architecture</A></H2>

As creating C++ preprocessor or specialized compiler requires huge amount of work and
still can not solve all the problems, I decide to implement first and last approaches 
(getting type information from debug information and let programmer to provide this information).
So <I>CppReflection</I> product consists of the following parts:

<OL>
<LI>Common core: descriptors for classes, fields, methods which provide all
reflection functionality.
<LI>Helpers for describing type information by programmer: set of macros, overloaded methods,
and supplementary classes which makes it possible for programmer to specify only names
of fields and methods and all other information (type, offset, size, profile) is calculated
automatically. Using this helpers make task of describing types more convenient and less error prone.
<LI>Library which is used to extract information from ELF, COFF and some other executable files
formats.
</OL>  

Reflection API is described in <A HREF = "html/index.html">this document</A> generated by Doxygen.
Code for extracting type information from debug data was taken from GNU objdump utility. 
The rest of this chapter provide more information about describing types by programmer.<P>

It seems to be better to start with an example:
<PRE>
#include "reflect.h"
#include "typedecl.h"

class A { 
  public:
    int    i;
    char*  pc;
    double d;
  protected:
    long   larr[10];
    A**    ppa;    
    A*     pa;
  public:
    RTTI_DESCRIBE_STRUCT((RTTI_FIELD(i, RTTI_FLD_PUBLIC),
                          RTTI_PTR(pc, RTTI_FLD_PUBLIC),
                          RTTI_FIELD(d, RTTI_FLD_PUBLIC),
                          RTTI_ARRAY(larr, RTTI_FLD_PROTECTED),
                          RTTI_PTR_TO_PTR(ppa, RTTI_FLD_PROTECTED),
                          RTTI_PTR(pa, RTTI_FLD_PROTECTED)));
};

RTTI_REGISTER_STRUCT(A, 0);
</PRE>

So, you see that there two special macros <code>RTTI_DESCRIBE_STRUCT</code> and
<code>RTTI_REGISTER_STRUCT</code>. 
First one describes class components and is used inside declaration of the class.
And <code>RTTI_REGISTER_STRUCT</code> macro should be used in implementation module
(<code>.cpp</code> file) to register class descriptor in repository. 
Class fields should be described using the following macros:<P>

<TABLE BORDER>
<TR><TH>Macro</TH><TH>Field type</TH></TR>
<TR><TD><code>RTTI_FIELD</code></TD><TD>Scalar, structure or class</TD></TR> 
<TR><TD><code>RTTI_PTR</code></TD><TD>Pointer to scalar, structure or class</TD></TR> 
<TR><TD><code>RTTI_PTR_TO_PTR</code></TD><TD>Pointer to pointer to scalar, structure or class</TD></TR> 
<TR><TD><code>RTTI_ARRAY</code></TD><TD>One dimension array of scalars, structures or classes</TD></TR> 
</TABLE><P>

First parameter of these macros specifies field and second - bit mask of arbitrary flags (qualifiers)
for this field. There are some predefined flags:


<PRE>
    enum RTTIFieldFlags { 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -