跟我学c++高级篇——基础类型和POD结构体反射

C++ 反射机制(实例讲解) C++反射机制 阅读详情

一、基础类型反射

在前面以枚举体和函数进行了反射的实践,在其中也提到过,其实更应该进行反射的是类(结构体)。毕竟现在以面向对象编程基本已经普及,类(结构体)的应用几乎已经是无法避免的。所以对类(后面再提到类即包含结构体)的反射,其实应用的范围会更大。
对基础类型和POD类型的结构体进行反射,一般就是下面的情况:
1、对名称进行反射来动态获取和创建对象
2、对结构体变量的反射
这里只是POD类型的结构体,复杂的在后面再进行分析,当然这里也包含简单类。

二、实现机制

在前面反复进行反射的分析说明时,其实可以发现,反射实现常用的机制还是比较多的,但一般来说应用的比较多的就是使用模板和宏配合来实现。当然在具体的实现过程中可能需要一些具体的编译器或者辅助库的实现。另外在c++新标准下也提供了一些方法比如可以使用std::tuple来实现类的反射。
其实原理仍然是前面分析过的文章中的思路,即获取名称字符串与结构体之间的映射,其成员(变量)需要进行遍历注册。这样就可以在后面的代码中利用字符串来搞定这些对象获取及动态创建对象等。
这里需要再次说明的是:
1、是否需要侵入式处理
2、是否开销最小甚至是零开销
3、是否反射完全,即包括私有数据等是否可以得到
这三个条件是实现一个好的反射框架的前提。

三、实现

下面看一个初步的实现:

#pragma once
#include <string>
#include <array>
#include <stddef.h>
#include <iostream>

typedef unsigned int uint32;

struct Type {
	std::string typeName;
	size_t size;
};

//获得结构体成员类型信息
template<typename T>
 Type* GetFieldType();
#define GET_OBJECT_TYPE(TYPE) \
template<> \
Type* GetFieldType<TYPE>() { \
static Type t; \
  t.typeName = #TYPE; \
  t.size = sizeof(TYPE); \
  return &t; \
};\

//成员反射信息
struct Member {
	Type* t;
	std::string name;
	size_t offset;
};
constexpr int ARRAY_NUM = 4;

// 存储结构体的相关成员
struct ClassArray {
	std::array<Member, ARRAY_NUM> members;
};

//遍历获得类或结构体的成员信息
template<typename T>
const ClassArray* GetClass();
#define BEGIN_MEMBERS_FOR(CLASS)  \
template<> \
const ClassArray* GetClass<CLASS> () { \
  using ClassType = CLASS; \
  static ClassArray cArray; \
  enum { BASE = __COUNTER__ }; \

#define OBJECT_MEMBER(NAME)  \
  enum { NAME##ID = __COUNTER__ - BASE - 1}; \
  cArray.members[NAME##ID].t = GetFieldType<decltype(ClassType::NAME)>();\
  cArray.members[NAME##ID].name = { #NAME };  \
  cArray.members[NAME##ID].offset = offsetof(ClassType, NAME);\

#define END_MEMBERSS \
  return &cArray; \
};\

//获得类型信息宏处理
GET_OBJECT_TYPE(char)
GET_OBJECT_TYPE(short)
GET_OBJECT_TYPE(int)
GET_OBJECT_TYPE(uint32)

struct Data {
	int id;
	short len;
	char sex;
	uint32 size;
};

//处理结构体的反射
BEGIN_MEMBERS_FOR(Data)
OBJECT_MEMBER(id);
OBJECT_MEMBER(len);
OBJECT_MEMBER(sex);
OBJECT_MEMBER(size);
END_MEMBERSS

int main()
{
	auto x = GetClass<Data>();
	std::cout<<"TestStruct:"<<std::endl;
	for (auto &x :x->members){
		std::cout<<x.name<<",offset:"<<x.offset<<",type:"<<x.t->typeName<<std::endl;
	}
	return 0;
}

上面有两个宏需要注意,一个是__COUNTER__,一个是offsetof,前者是GNU的的一扩展,用来处理得到一个唯一键值;后者则是通过偏移量来获得类或结构体内成员的位置(也可以反过来理解)。
上面的代码其实很容易理解,注释写得比较清晰了,这里再简单的说明一下:
1、首先定义两个信息类:一个是基础的Type类,用来获得类型的相关信息,如名字等;另外一个是Member类,用来处理成员的相关信息
2、通过宏GET_OBJECT_TYPE来得到具体的类型信息,这个用来哪个就需要注册一个
3、通过宏OBJECT_MEMBER来得到成员信息并和刚刚得到的类型信息绑定
4、利用模板的显示实例化来实现不同的信息的具体处理
其实上面的代码只是一个基础的版本,如果不习惯使用宏的,可以将成员函数等宏实现改成普通的静态函数来实现。但是完全不使用宏,可能操作起来还是有些看起来不方便。这个根据个人的喜好自己斟酌。

四、std::tuple的实现

这个在这里简单介绍一下,回头在后续再展开分析。在前边的“面向切片编程”中,提到了使用tuple_element可以获得std::tuple中的类型。而在反射中,不就是一个类型获取的过程么?

//利用变参模板和tuple的特性来获取指定的类型
template<typename ...Types>
class ProxyObjectTypes {
  public:
  template<std::size_t ID>
  struct GetType {
    using Type = typename std::tuple_element<ID, std::tuple<Types...>>::type;
  };
};
//C++11定义的方式:
template <std::size_t I, class T>
using tuple_element_t = typename tuple_element<I, T>::type;

那么,这就可以通过显示实例化不同的模板函数参数版本来处理不同的数据类型,是不是和上面的代码中的类似。其实使用模板处理反射类型大多也是这么个路子。那么就可以写一个getType的模板函数,通过decay(decltype)和if constexpr来在编译期得到想要的数据类型。
可以通过下面的这个判断来确定std::tuple中的类型是否为自己需要的数据类型。这样就可以安全的获得类型信息的数据类型,进而得到数据对象。

constexpr int count_first_falses() { return 0; }

template <typename... T>
constexpr int count_first_falses(bool b, T... t)
{
  if (b)
  {
    return 0;
  }
  else
  {
    return 1 + count_first_falses(t...);
  }
}

template <typename E, typename... T>
decltype(auto) tuple_get_by_type(const std::tuple<T...>& tuple)    
{
  return std::get<count_first_falses((std::is_same<T, E>::value)...)>(tuple);
}

decltype(auto) getType(const std::tuple<int,int> &t)
{
  return tuple_get_by_type(t);
}

如果只是单纯的想获得类型可以用下面的方法:


#include <string>
#include <tuple>

template <typename T> T* getType() {  return nullptr;}
template <> int* getType<int>() { return new int; }
template <> std::string* getType<std::string>() { return new std::string; }

int main()
{
    using T = std::tuple<int, std::string>;
    getType<std::tuple_element<0, T>::type>();
    getType<std::tuple_element_t<1, T>>();

   return 0;
}

代码不难,基本上看一下就能明白。

五、总结

由简入繁,从基本到深入总是需要一个过程,学习反射也是如此。写代码是为了把学习的知识验证一下,同时可以更加深刻的理解知识。开发者们经常遇到这种场景,几行简单的代码,琢磨半天也确定不了什么意思,但是上机一调试,就恍然大悟。这就是侯捷教师的那句话“源码之前,了无秘密”。
反射还是有些难度的,所以这个系列会慢慢增加。

【C/C++】什么是POD(Plain Old Data)类型 只包含标量类型(如整数、浮点数、指针等)或者其他 POD 类型的成员。没有用户自定义的构造函数、析构函数或拷贝控制成员没有虚函数或虚继承可以通过memset和memcpy进行内存的简单复制和初始化。这些标准在 C++03 标准中被定义。根据这个定义,POD 类型可以被视为简单的、平凡的数据类型,可以进行一些底层的操作,如内存复制、比较和序列化等。POD 类型通常用于与 C 语言进行交互、进行低级别的内存操作或进行数据序列化和传输。 阅读详情

相关推荐

C++17编译期反射实现结构体自动序列化与遍历

序列化是将数据结构转换为可存储或传输格式的过程,其核心原理在于将对象状态编码为字节流或文本。在C++工程实践中,手动为每个结构体编写序列化代码繁琐且易错,而编译期反射技术能自动生成这些代码,显著提升开发效率。通过C++17的结构化绑定和折叠表达式,可以在编译期分析结构体布局,实现非侵入式的成员遍历。这种技术方案尤其适用于网络通信和数据持久化场景,能够为POD类型结构体提供类型安全的自动序列化支持。

weixin_31292729的博客 264

跟我学c++高级篇——反射

其实反射也可以放到模板元编程中来进行分析,但是为了更好的讲解一些c++的高级特性,还是把它分离了出来。c++的许多高级的特性,在国内的大多数应用场景上,其实是应用不到的。原因是,这些高级特性大多是在基础库支持或者基础软件上才用的。而这恰恰是国内的软肋。知已知彼,百战不殆。看到有什么不足,才能更好的补齐它。共同努力!

fpcc的专栏 8001

C++反射机制:原理剖析、主流库对比与RTTR实战应用

反射(Reflection)是编程语言中一项重要的元编程能力,它允许程序在运行时检视和操作自身的类型结构。其核心原理在于突破编译期的信息封装,通过构建类型信息数据库或利用编译期元编程技术,动态获取类的成员、方法和继承关系。这项技术的核心价值在于极大地提升了代码的灵活性与可维护性,能够自动化处理原本需要大量手动编码的通用逻辑。在C++工程实践中,反射的典型应用场景包括实现通用的序列化/反序列化系统、构建支持动态属性的编辑器、简化远程过程调用(RPC)的参数编解码,以及为脚本语言提供绑定层。针对C++语言本身缺

weixin_34323858的博客 363

C++反射机制的实现

1.什么是反射 首先看一个问题:如何通过类的名称字符串来生成类的对象,比如有一个类Class A,那么如何通过类名称字符串“Class A”来创建类的对象呢? C++本身是不支持通过类名称字符串"Classxx"来生成对象的,也就是说我们可以使用ClassXX* object =new ClassXX;来生成对象,但是不能通过ClassXX* object=new "ClassXX";来生成对象。 要想解决这个问题就要用到反射,我们先看下维基百科的定义:反射是指计算机程序在运行时可以访问、检测和修..

C/C++、嵌入式开发、深度学习算法、模型部署与推理优化 1万+

C++序列化库xpack:告别手动解析,实现结构体与JSON/XML/BSON自动转换

序列化是将数据结构或对象状态转换为可存储或传输格式的过程,是网络通信、数据持久化和API交互的基石。其核心原理在于定义数据与字节流间的映射规则,传统手动解析方式易出错且难以维护。现代序列化技术通过编译时元编程或运行时反射自动生成编解码逻辑,显著提升开发效率和代码健壮性。xpack作为C++开源库,正是这一技术的优秀实践。它采用头文件库设计,通过宏和模板元编程在编译时为结构体注入序列化代码,实现零开销抽象。同时,其适配器模式统一了JSON、XML、BSON等多种格式的接口。该库极大地简化了C++后端开发中处理

conghuang7343的博客 516

C++运行时反射系统实现:从原理到实战的轻量级解决方案

反射(Reflection)作为一种元编程技术,允许程序在运行时检视和操作自身的类型信息。其核心原理是通过维护类型元数据(如类名、成员变量、方法等)的注册表,实现动态的类型发现与对象操纵。在C++这类静态语言中实现反射,能显著提升代码的灵活性与可维护性,其技术价值在于减少重复的样板代码,支持序列化、数据绑定、脚本集成等高级功能。典型的应用场景包括游戏引擎的对象序列化、UI编辑器的属性动态编辑以及插件系统的动态加载。本文聚焦于C++运行时反射系统的构建,通过非侵入式设计和类型擦除技术,实现了一个轻量级但实用的

csxc65837的博客 383

跟我学c++高级篇——类反射

反射对c++是不是一种鸡肋,这个还真不好说。不过有一句话可以引入进来,“发展是硬道理”,只要是不断的发展,就会有机会。而停滞不前的空谈理论,一定是没有前途的。至于以后反射在c++后续标准里会成为什么样子,大家拭目以待即可。

fpcc的专栏 1580

基于Clang的C++反射实现:原理、构建与性能优化

反射机制是编程语言中实现运行时自省的核心技术,它允许程序在运行时动态获取和操作类型信息。其原理是通过编译器或解释器在编译期或运行期收集并存储类型元数据,从而突破静态类型系统的限制。这项技术的核心价值在于提升代码的灵活性和可维护性,尤其在需要动态处理对象、实现通用序列化/反序列化、构建数据驱动工具链以及进行脚本绑定的场景中至关重要。本文聚焦于C++语言,探讨如何利用Clang编译器前端这一强大工具,以非侵入式的方式构建高效的运行时反射系统。通过解析抽象语法树(AST)提取类型信息,并设计紧凑的运行时数据结构,

weixin_33743661的博客 356

从C++17到C++26,反射机制演进全解析,掌握下一代系统级编程利器

掌握C++26反射机制,显著提升元编程效率。通过2025全球C++及系统软件技术大会:C++26反射机制的元编程效率提升案例,解析从C++17到C++26的演进路径,涵盖编译期反射、泛型优化与系统级应用实践,实现代码简洁性与运行性能双提升,值得收藏。

LogicPlex的博客 779

C++无RTTI反射系统:宏驱动实现与性能优化实践

反射机制是提升大型软件框架灵活性与数据驱动能力的关键技术,它允许程序在运行时查询和操作类型信息。其核心原理是通过构建类型元数据表,将编译期类型信息映射到运行时数据结构中,从而在不依赖编译器RTTI的情况下实现动态类型操作。这项技术的核心价值在于解耦数据与逻辑,为序列化、编辑器集成、脚本绑定等场景提供统一基础设施。在游戏引擎、编辑器工具链及高性能嵌入式系统等应用场景中,禁用RTTI是常见需求,因此无RTTI的反射系统成为刚需。本文通过宏驱动与静态注册方案,深入解析了类型信息表构建、成员偏移量安全计算、多态序列

weixin_33912246的博客 316

C++编译期反射:原理、实现与应用场景

编译期反射是C++模板元编程的重要技术,通过在编译阶段完成类型信息提取和代码生成,实现零运行时开销的类型自省能力。其核心原理基于模板特化、SFINAE规则和constexpr函数,结合C++17的结构化绑定技术,能够高效处理复杂类型。这种技术在序列化/反序列化、游戏引擎组件系统和单元测试框架等场景中具有显著优势,相比运行时反射可完全消除性能开销。以Boost.Hana和MagicGet为代表的现代库方案,通过模板元编程实现了低侵入性的成员反射,大幅减少了样板代码量。在工程实践中,编译期反射可提升开发效率,同

weixin_30731305的博客 393

C++反射系统Metareflect:从原理到实现,赋能运行时类型自省

反射是编程语言中一项重要的元编程能力,它允许程序在运行时检查和修改自身的结构和行为。其核心原理是通过维护一套类型元信息数据库,将编译期的类型信息(如类名、成员变量、方法等)以数据结构的形式保存下来,供运行时查询和操作。这项技术的核心价值在于实现数据与行为的解耦,极大地提升了代码的灵活性和可维护性。在C++这类静态类型语言中,由于缺乏原生支持,实现反射通常需要借助模板元编程、预处理器宏等编译期技术来构建轻量级的类型描述系统。这种技术广泛应用于需要高度动态性和数据驱动的场景,例如游戏引擎中的属性编辑器、通用序列

424

c/c++ 结构体反射功能

c/c++ 中如果要打印结构体,不需要再复杂的输入n行printf了,一行就搞定 char *pMsg = CLoadDumpDll::Dump("MyStruct",&my); 时间有限,目前还只是支持基本类型的打印,哪些类型,参考test .cpp。

编译期序列化真的来了吗?C++26反射机制全解析,速看!

掌握C++26反射机制,轻松实现编译期序列化代码生成。适用于网络通信、持久化存储等场景,无需运行时开销,提升性能与安全性。详解核心语法与实际应用方法,开发效率飞跃,值得收藏。

InstrGap的博客 533

Win10家庭版没有Hyper-V?教你一招轻松解决(含避坑指南)

本文详细介绍了在Win10家庭版中启用Hyper-V的完整实战指南。通过DISM工具链绕过系统版本限制,无需重装系统即可完整启用所有Hyper-V组件,适用于开发者测试多系统环境和安全隔离应用场景。文章包含详细操作步骤、常见问题解决方案及性能优化配置,帮助用户轻松解决Win10家庭版没有Hyper-V的问题。

weixin_29239661的博客 493

详细推导波特图增益和相位曲线

文章来源:https://mp.weixin.qq.com/s/UCy9mRRok5Hc9qHq3qde5g 今天这篇文章想把近段时间关于波特图方面学习的内容整理一下。波特图将会是梳理闭环控制这个系列的开始。目前的计划是,以无源器件为基础,然后结合运放,再过渡到开关电源的环路控制方面。如果对这方面感兴趣的朋友,可以持续一起学习起来,目标就是掌握开关电源的闭环控制。 1. 什么是波特图? 波特图最常见的应用是在线性非时变的系统中,用于对传递函数的增益和相位进行分析,从而判断出系统随频率的响应是否稳定。因此,波

ltqdxl的博客 2万+

Qt结构体的定义和使用

在Qt中,结构体(struct)是C 的基础数据类型,用于封装相关数据成员。

2501_93580012的博客 554

多尺度Transformer+特征融合新范式,算力减半精度猛增

在大模型时代,多尺度特征融合与Transformer架构的结合正成为研究热点。多尺度特征融合能够捕捉数据在不同尺度上的关键信息,而Transformer架构凭借其强大的并行处理能力和对长距离依赖的建模能力,为复杂数据处理提供了新的思路。这种结合在处理多模态数据时展现出巨大潜力。

Tulingxueshu的博客 1057

Boost.PFR:无需宏或样板代码,为用户自定义类型带来std::tuple般体验的革命性C++库

Boost.PFR是一个功能强大的C++库,它允许开发者像操作`std::tuple`一样处理用户自定义类型,而无需编写任何宏或样板代码。这个库利用C++11及以上标准的特性,为结构体和类提供了自动反射功能,极大地简化了代码编写并提高了开发效率。 ## 🌟 Boost.PFR的核心优势 ### 无需宏定义,零样板代码 传统的结构体反射通常需要大量的宏定义或手动编写访问函数,而Boost.PF

gitblog_00618的博客 519

GEO数据库数据下载方法总结

#GEO数据下载 GEO是生信分析经常用到的数据库。经常需要从中获取表达矩阵,平台信息,meta信息等,本博文总结了几种下载GEO数据的方法,各有优劣,实际应用过程中自行选择适合自己的。 ##方法一:直接从浏览器中下载 以数据集GSE1001为例, 可以直接点击“Series Matrix Files”获取该样本txt格式的表达谱数据,一般我们认为这种处理过的表达谱数据是没有问题的,当然,具体情况具体分析。 打开下载的文件可以看到许多“#”开头的行,这些是注释信息,一般关注这些注释信息中的“data pr

sakoko_的博客 4万+

Python+Appium实现泛微OA自动打卡:5分钟搭建移动端自动化脚本

移动端自动化测试是软件测试与办公自动化领域的重要技术方向,其核心原理是通过程序模拟用户对手机应用界面的操作,实现重复性任务的自动执行。Appium作为主流的开源移动端自动化框架,基于WebDriver协议,支持跨平台且无需修改被测应用,为自动化脚本开发提供了标准化接口。在工程实践中,结合Python简洁的语法和丰富的生态,可以快速构建稳定可靠的自动化解决方案。这一技术组合的价值在于能够高效处理“重复性、低价值、高频率”的日常操作,例如考勤打卡、数据填报等办公场景,显著提升工作效率。本文以泛微OA Emobi

weixin_28836875的博客 389

C++反射机制实现原理与RTTI替代方案深度解析

反射是编程语言中一项重要的元编程能力,它允许程序在运行时自省和操作自身的结构信息,如类型、成员变量和方法。其核心原理是通过维护一套类型元数据系统,将编译时已知的类型信息(如名称、大小、成员布局)以数据结构的形式保存下来,供运行时查询和调用。这项技术的核心价值在于实现了代码的动态性和灵活性,能够大幅提升框架、库和工具的开发效率。在C++中,由于标准库提供的运行时类型识别(RTTI)功能有限且存在性能开销,开发者常需寻求替代方案以满足序列化、对象关系映射、脚本绑定等高级应用场景的需求。本文聚焦于C++反射机制的

weixin_34248487的博客 546

RT-DETR改进策略【卷积层】| CGblock 内容引导网络 利用不同层次信息,提高多类别分类能力 (含二次创新)

本文记录的是利用中的模块优化的目标检测网络模型。通过局部特征提取器、周围环境提取器、联合特征提取器和全局环境提取器来提取局部特征、周围环境和全局环境信息,充分利用不同层次的信息。本文将其应用到中,并进行二次创新,使网络能够更好的处理多类别目标的分类能力。CGNet: A Light-Weight Context Guided Network for Semantic Segmentation1️⃣ 首先通过局部特征提取器floc(∗)floc(*)floc(∗)和周围环境提取器fsur(∗)f_{sur }

Limiiiing的博客 1348

C++通用字节序转换接口:基于模板的跨平台网络编程解决方案

字节序(Endianness)是计算机数据存储的基础概念,描述了多字节数据在内存中的排列顺序,主要分为大端序(Big-Endian)和小端序(Little-Endian)。其原理源于CPU架构差异,直接影响数据的正确解析。理解字节序对于实现跨平台数据交换、网络通信和文件解析等技术至关重要。在C++网络编程等工程实践中,处理字节序转换的代码往往分散且类型特定,降低了可维护性。通过引入C++模板元编程,可以构建类型安全的通用转换接口,自动适配各种内置类型,并利用编译器内置函数(如__builtin_bswap)

weixin_30675247的博客 561

YOLOv8与UNetV2融合:一种面向目标检测与图像分割的混合方法【附核心代码】

我们提出了一种基于YOLOv8和UNetV2相结合的混合架构。该架构利用YOLOv8作为主干进行目标检测,同时在YOLOv8的特征提取过程中,引入UNetV2来进行图像分割任务的增强。在该架构中,YOLOv8负责大范围目标检测和位置预测,而UNetV2则在检测网络的特征图基础上,通过其高效的上下文信息提取和细节恢复能力,进一步优化分割任务。在本文中,我们提出了一种改进YOLOv8的方法,通过引入图像分割网络UNetV2来提高图像分割检测性能。

一键难忘的博客 3524

YOLO11改进-注意力-引入Deformable Large Kernel Attention (DLKA) 解决多尺度、小目标、遮挡等问题

Deformable Large Kernel Attention (DLKA) 是一种用于视觉任务的注意力机制,旨在提升模型在处理不同尺寸和形状对象时的灵活性和性能。DLKA 的设计灵感源自传统的注意力机制,但通过引入可变形核(deformable kernel)来增强对局部特征的适应能力。

qq_64693987的博客 4041
上一篇: 跟我学c++中级篇——面向切片编程
下一篇: assert和static_assert及#error的使用
fpcc
fpcc 新星创作者: C/C++技术领域 新星创作者: C/C++技术领域
博客等级 码龄22年 4038粉丝 1185原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值