注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

进击の架构师

 
 
 

日志

 
 

[C/C++]运行期构建C++类型系统  

2014-04-04 22:44:46|  分类: C/C++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

现代高级的面向对象语言(如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);

         }

}



  评论这张
 
阅读(805)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017