文档章节

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

梁欢
 梁欢
发布于 2014/04/04 22:49
字数 1047
阅读 142
收藏 6

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


本文转载自:http://blog.163.com/lvan100@yeah/blog/static/6811721420143410336716/

梁欢
粉丝 3
博文 19
码字总数 0
作品 4
海淀
高级程序员
私信 提问
构建简单的C++运行时反射类型系统

在《运行期构建C++类型系统》这篇文章中,我构建了一套简单的运行期C++类型系统,当时提到了它的应用场景有字符串映射到类型,本篇文章展示的是它的简单实现。 Metadata.h #ifndef METADATA_...

梁欢
2014/04/05
684
0
从 C++98 到 C++17,元编程是如何演进的? | 技术头条

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/csdnnews/article/details/86297148 作者 | 祁宇 责编 | 郭芮 出品 | CSDN(ID:CSDNnews) 不断出现的C++新的...

CSDN资讯
01/11
0
0
深入理解C++的动态绑定和静态绑定

为了支持c++的多态性,才用了动态绑定和静态绑定。理解他们的区别有助于更好的理解多态性,以及在编程的过程中避免犯错误,需要理解四个名词: 1、对象的静态类型:对象在声明时采用的类型。...

鉴客
2011/05/19
12.5K
6
深入理解C++的动态绑定和静态绑定

为了支持c++的多态性,才用了动态绑定和静态绑定。理解他们的区别有助于更好的理解多态性,以及在编程的过程中避免犯错误。 需要理解四个名词: 1、对象的静态类型:对象在声明时采用的类型。...

晨曦之光
2012/06/06
48
0
嵌入式开发之C++基础学习笔记1--综合比较HelloWorld示例

选择C++的理由: 1)C++语言是由C语言扩充而来。它是一门混合型的语言,既支持传统的结构化程序设计,又支持面向对象的程序设计,这使得C++非常流行。它在编程中支持面向对象。因此,它比C更...

吴锦涛
2012/12/16
688
1

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot + Mybatis-Plus 集成与使用(二)

前言: 本章节介绍MyBatis-Puls的CRUD使用。在开始之前,先简单讲解下上章节关于Spring Boot是如何自动配置MyBatis-Plus。 一、自动配置 当Spring Boot应用从主方法main()启动后,首先加载S...

伴学编程
昨天
7
0
用最通俗的方法讲spring [一] ──── AOP

@[TOC](用最通俗的方法讲spring [一] ──── AOP) 写这个系列的目的(可以跳过不看) 自己写这个系列的目的,是因为自己是个比较笨的人,我曾一度怀疑自己的智商不适合干编程这个行业.因为在我...

小贼贼子
昨天
7
0
Flutter系列之在 macOS 上安装和配置 Flutter 开发环境

本文为Flutter开发环境在macOS下安装全过程: 一、系统配置要求 想要安装并运行 Flutter,你的开发环境需要最低满足以下要求: 操作系统:macOS(64位) 磁盘空间:700 MB(不包含 IDE 或其余...

過愙
昨天
6
0
OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
昨天
2.7K
16
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
昨天
42
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部