运行期构建C++类型系统

2014/04/04 22:49
阅读数 217

现代高级的面向对象语言(如JavaC#等)一般会提供一种称之为“反射”的特性,通过它可以动态的创建类型实例,将类型绑定到现有对象,或从现有对象中获取类型,还可以调用类型的方法及访问其字段和属性。“反射”的功能非常强大,其中一种比较重要的应用是将JSON字符串直接映射成某个类型的变量。

         相对上面提到的那些面向对象语言而言,同样是面向对象的C++语言的类型系统功能还是比较弱的,当然这也有其这么做的原因。那么有没有办法在现有的C++类型系统上提供一些有益的补充呢?本文试着给出一些答案。

         如果您使用过VC编译器,那么您也许可以尝试一下cl命令“/d1 reportAllClassLayout”,它可以在编译期打印类型的内存结构,例如下面这个展示:

1>  class _PMD size(12):

1>   +---

1>   0       | mdisp

1>   4       | pdisp

1>   8       | vdisp

1>   +---

上面展示的这个类型是_PMD,内存大小为12字节,其中从头到尾变量依次是mdisppdispvdisp,这三个变量每个占用了4个字节。

         为了在运行期也能够的获取类型的内存信息,首先我们需要定义一个变量需要的信息结构:

/*
 * 成员变量的元数据
 */
struct FieldMetadata
{
         // 成员变量的名称
         string name;
 
         // 成员变量的类型
         string type;
 
         // 成员变量的地址
         size_t offset;
 
         FieldMetadata(string name, string type, size_t offset)
         {
                   this->name = name;
                   this->type = type;
                   this->offset = offset;
         }
};

         我们想一下,既然是类型的元数据信息,那么也就是与具体的类型实例是无关的,元数据信息应该属于类型本身,那么将元数据信息定义成static变量是再适合不过的了:

static vector<FieldMetadata> fieldinfo;

         每当给类型增加一个成员变量的时候,我们除了定义一个成员变量以外,还需要将它的类型和内存信息注册到元数据信息中:

         int a;
fieldinfo.add(FieldMetadata(“a”, “int”, 0));
         int b;
fieldinfo.add(FieldMetadata(“b”, “int”, 4));
         int c;
fieldinfo.add(FieldMetadata(“c”, “int”, 8));

         定义一个变量很容易,但是要自动执行一个函数却很难,下面我要讲的涉及到了C++模板,元编程,offsetof,宏定义等需要深厚的C++功底才能理解的内容,要是让我一步一步的讲的细致入微,我担心力有所不逮。如果您有深厚的C++功底,那么我接下来要讲的内容其实又很简单,您肯定能一看就懂。下面呈上我实作的代码。

 
#include <vector>
#include <string>
using namespace std;
 
 
/*
 * 成员变量的元数据
 */
struct FieldMetadata
{
         // 成员变量的名称
         string name;
 
         // 成员变量的类型
         string type;
 
         // 成员变量的地址
         size_t offset;
 
         FieldMetadata(string name, string type, size_t offset)
         {
                   this->name = name;
                   this->type = type;
                   this->offset = offset;
         }
};
 
 
/*
 * 声明结构体类型
 */
#define Declare_Struct(class_type) \
private: \
 \
typedef class_type this_class; \
 \
template<int N> class Init_I \
{ \
public: \
         Init_I(vector<FieldMetadata>& metas) \
         {} \
}; \
 
 
/*
 * 定义结构体变量
 */
#define Define_Field(var_index, var_type, var_name) \
public: \
 \
var_type var_name; \
 \
private: \
 \
template<> class Init_I<var_index> \
{ \
public: \
         Init_I(vector<FieldMetadata>& metas) \
         { \
                   FieldMetadata fmd(#var_name, typeid(var_type).name(), offsetof(this_class, var_name)); \
                   metas.insert(metas.begin(), fmd); \
         } \
}; \
 
 
/*
 * 定义结构体元数据
 */
#define Define_Metadata(var_count) \
public: \
 \
static vector<FieldMetadata> fieldinfo; \
 \
private: \
 \
template<int N> class CallInits \
{ \
public: \
         CallInits(vector<FieldMetadata>& metas) \
         { \
                   Init_I<N> in(metas); \
                   CallInits<N-1> ci(metas); \
         } \
}; \
 \
template<> class CallInits<1> \
{ \
public: \
         CallInits(vector<FieldMetadata>& metas) \
         { \
                   Init_I<1> in(metas); \
         } \
}; \
 \
static vector<FieldMetadata> Init() \
{ \
         vector<FieldMetadata> fmd; \
         CallInits<var_count> ci(fmd); \
         return fmd; \
} \
 
 
/*
 * 实现结构体类型
 */
#define Implement_Struct(class_type) \
vector<FieldMetadata> class_type::fieldinfo = class_type::Init(); \
 
 
struct Test
{
 
         Declare_Struct(Test);
 
         Define_Field(1, int, a)
 
         Define_Field(2, int, b)
 
         Define_Field(3, int, c)
 
         Define_Metadata(3)
 
};
 
 
Implement_Struct(Test)
 
 
void main()
{
         printf("struct size : %d \n", sizeof(Test));
 
         printf("fieldinfo size : %d \n", Test::fieldinfo.size());
 
         printf("struct layout : \n");
         for (auto iter = Test::fieldinfo.begin(); iter != Test::fieldinfo.end(); iter++)
         {
                   printf("%s, %s, %d \n", (*iter).name.c_str(), (*iter).type.c_str(), (*iter).offset);
         }
}


展开阅读全文
打赏
0
6 收藏
分享
加载中
更多评论
打赏
0 评论
6 收藏
0
分享
返回顶部
顶部