C++:获取类成员的偏移量

2024-06-06 22:08
文章标签 c++ 获取 成员 偏移量

本文主要是介绍C++:获取类成员的偏移量,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

出自:http://blog.163.com/henan_lujun/blog/static/19538333201078111820803/

第一种方式是MFC里使用广泛的宏对空对象成员取地址

#define OFFSET(structure, member) ((int)&((structure*)0)->member);

正如我们平时通过某对象的地址指针访问某个成员变量一样,这里只是强制使用0作为该地址,但区别是并没有通过该地址去访问成员变量,而只是用&操作符来获取该成员变量的地址,所以不会出现访问违规的情况。

object member address = object address + member offset

因此当对象地址为0时,对对象成员取地址得到的就是该成员在对象中的偏移量。只是对虚基类中的成员无法通过此种形式获得其偏移量——一般的编译器都需要通过从虚表中获得虚基类部分在对象中的偏移量,而空对象其vptr无效,所以无法获得虚表,因此也无法获得虚基类部分的偏移量。

    Point3D *point = 0;

    cout << "&NULLPointer._x " << &(point->_x<< endl;

    cout << "&NULLPointer._y " << &(point->_y<< endl;

    cout << "&NULLPointer._z " << &(point->_z<< endl;

输出:

&NULLPointer._x 0

&NULLPointer._y 0x4

&NULLPointer._z 0x8

 

 

第二种方式是通过类成员指针获得成员偏移量

另一种方式是通过域操作符取成员变量的地址。例如一个类Testint 型成员变量x,则可以通过int Test::* pOffset = &Test::x 获得该偏移量,然后通过

int nOffset = reinterpret_cast<int>(*(void**)(&pOffset))将其转化为整型量。

int Point3D::* offsetx = &Point3D::_x;

int Point3D::* offsety = &Point3D::_y;

int Point3D::* offsetz = &Point3D::_z;

 

int nOffsetx = reinterpret_cast<int>(*(void**)(&offsetx));

int nOffsety = reinterpret_cast<int>(*(void**)(&offsety));

int nOffsetz = reinterpret_cast<int>(*(void**)(&offsetz));

cout << "nOffsetx= reinterpret_cast<int>(*(void**)(&offsetx))"<< nOffsetx <<endl;

cout << "nOffset = reinterpret_cast<int>(*(void**)(&offsety))" << nOffsety <<endl;

cout << "nOffsetz= reinterpret_cast<int>(*(void**)(&offsetz))"<< nOffsetz <<endl;

 

输出:

int nOffsetx = reinterpret_cast<int>(*(void**)(&offsetx)) =  0

int nOffsety = reinterpret_cast<int>(*(void**)(&offsety)) =  4

int nOffsetz = reinterpret_cast<int>(*(void**)(&offsetz)) =  8

 

上述的输出方式过于麻烦,如果用printf则可以直接作为整数输出。

    printf ( "int Point3D::* offsetx = %d\n",offsetx );

    printf ( "int Point3D::* offsety = %d\n",offsety );

    printf ( "int Point3D::* offsetz = %d\n",offsetz );

 

    cout << "cout << int Point3D::* offsetx =  " << offsetx << endl;

    cout << "cout << int Point3D::* offsety =  " << offsety << endl;

    cout << "cout << int Point3D::* offsetz =  " << offsetz << endl;

输出结果:

int Point3D::* offsetx = 0

int Point3D::* offsety = 4

int Point3D::* offsetz = 8

cout << int Point3D::* offsetx =  1

cout << int Point3D::* offsety =  1

cout << int Point3D::* offsetz =  1

这里由于没有为Point3D定义<<操作,所以编译器这里自己偷偷的帮着你进了转化,输出结果就为1。用printf则可以直接将偏移量输出出来;

 

特别说明:

特别说明:

l        经过试验,在多重继承的情况下,使用第二种方式来获取Derived类的第二个基类中成员在Derived类对象中的偏移量,获得的结果却和直接对第二个基类进行取偏移量的结果相同,这一点的猜测是:多重继承中第二个(乃至后面)的成员的偏移量仍然按照基类中的布局显现——然而这明显和实际的内存布局情况不符,而且关于这点,还没有找到相关的说明,存疑?鉴于这种情况,推荐使用第一种方式进行操作;

l        在存在虚拟继承的情况下,计算来自虚基类成员偏移量时,对空对象成员取指针的操作会失败,crash产生;猜测原因是:现在的编译器都是通过在virtual function table中放置virtual base class的偏移量的方式来索引虚基类成员,因此如果使用空对象,那么所计算得到虚基类成员的方式就是 ((virtual base class *)(0+offset))-> member,这样得到的地址是不可访问的,从而导致程序崩溃;



这篇关于C++:获取类成员的偏移量的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1037363

相关文章

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如

C#实现WinForm控件焦点的获取与失去

《C#实现WinForm控件焦点的获取与失去》在一个数据输入表单中,当用户从一个文本框切换到另一个文本框时,需要准确地判断焦点的转移,以便进行数据验证、提示信息显示等操作,本文将探讨Winform控件... 目录前言获取焦点改变TabIndex属性值调用Focus方法失去焦点总结最后前言在一个数据输入表单

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

通过C#获取PDF中指定文本或所有文本的字体信息

《通过C#获取PDF中指定文本或所有文本的字体信息》在设计和出版行业中,字体的选择和使用对最终作品的质量有着重要影响,然而,有时我们可能会遇到包含未知字体的PDF文件,这使得我们无法准确地复制或修改文... 目录引言C# 获取PDF中指定文本的字体信息C# 获取PDF文档中用到的所有字体信息引言在设计和出

python中os.stat().st_size、os.path.getsize()获取文件大小

《python中os.stat().st_size、os.path.getsize()获取文件大小》本文介绍了使用os.stat()和os.path.getsize()函数获取文件大小,文中通过示例代... 目录一、os.stat().st_size二、os.path.getsize()三、函数封装一、os

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

python获取当前文件和目录路径的方法详解

《python获取当前文件和目录路径的方法详解》:本文主要介绍Python中获取当前文件路径和目录的方法,包括使用__file__关键字、os.path.abspath、os.path.realp... 目录1、获取当前文件路径2、获取当前文件所在目录3、os.path.abspath和os.path.re

Java子线程无法获取Attributes的解决方法(最新推荐)

《Java子线程无法获取Attributes的解决方法(最新推荐)》在Java多线程编程中,子线程无法直接获取主线程设置的Attributes是一个常见问题,本文探讨了这一问题的原因,并提供了两种解决... 目录一、问题原因二、解决方案1. 直接传递数据2. 使用ThreadLocal(适用于线程独立数据)