C++从入门到精通——类对象模型

类对象模型

  • 前言
  • 一、如何计算类对象的大小
    • 问题
  • 二、类对象的存储方式猜测
    • 对象中包含类的各个成员
    • 代码只保存一份,在对象中保存存放代码的地址
    • 只保存成员变量,成员函数存放在公共的代码段
    • 问题
    • 总结
  • 三、结构体内存对齐规则
  • 四、例题
    • 结构体怎么对齐? 为什么要进行内存对齐?
    • 如何让结构体按照指定的对齐参数进行对齐?能否按照3、4、5即任意字节对齐?
    • 什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景


前言

类对象模型是一种编程概念,用于描述和实现面向对象编程(OOP)中的类和对象。在这个模型中,类定义了对象的结构和行为,包括数据成员(属性)和成员函数(方法)。对象是类的实例,具有类的所有属性和方法。类对象模型支持封装、继承和多态等OOP特性,使得代码更加模块化、可重用和易于维护。通过类对象模型,程序员可以创建复杂的软件系统,提高开发效率和代码质量。


一、如何计算类对象的大小

在C++中,可以使用sizeof运算符来计算类对象的大小。sizeof运算符返回指定类型或对象的大小(以字节为单位)。以下是计算类对象大小的示例代码:

#include <iostream>class MyClass {int x;double y;char z;
};int main() {MyClass myObject;size_t size = sizeof(myObject);std::cout << "对象的大小为:" << size << " 字节" << std::endl;return 0;
}

在这个示例中,我们定义了一个名为MyClass的类,它拥有一个int类型的成员变量x,一个double类型的成员变量y,以及一个char类型的成员变量z。然后,我们创建一个名为myObject的对象,并使用sizeof运算符计算myObject对象的大小。最后,将计算出的大小输出到控制台。

需要注意的是,sizeof运算符计算的是对象的静态大小,即编译时确定的对象的大小。它不包括动态分配的内存和对象引用的其他对象的内存。另外,sizeof运算符返回的大小是以字节为单位的无符号整数型,可以使用size_t类型来接收结果。

问题

class A
{
public:void PrintA(){cout << _a << endl;}
private:char _a;
};

类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类(含有成员变量和成员函数)的大小?

二、类对象的存储方式猜测

对象中包含类的各个成员

在这里插入图片描述
缺陷:每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一个类创建多个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间。那么如何解决呢?

代码只保存一份,在对象中保存存放代码的地址

在这里插入图片描述

只保存成员变量,成员函数存放在公共的代码段

在这里插入图片描述
在这里插入图片描述

问题

对于上述三种存储方式,那计算机到底是按照那种方式来存储的?

我们再通过对下面的不同对象分别获取大小来分析看下

class A1 {
public:void f1() {}
private:int _a;
};
// 类中仅有成员函数
class A2 {
public:void f2() {}
};
// 类中什么都没有---空类
class A3
{};

sizeof(A1) : ______ sizeof(A2) : ______ sizeof(A3) : ______

4 1 1

总结

  • 类对象的存储方式是按照只保存成员变量,成员函数存放在公共的代码段

  • 一个类的大小,实际就是该类中”成员变量”之和,须要注意内存对齐

  • 注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。

三、结构体内存对齐规则

结构体内存对齐是编译器为了提高执行效率和访问速度而进行的一种优化手段。

结构体内存对齐规则如下:

  1. 第一个成员在与结构体偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    注意:对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。
    VS中默认的对齐数为8
  3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

为了满足这些对齐规则,编译器在结构体中可能会插入一些填充字节,以确保成员变量按照规则排列。

例如,考虑以下结构体:

struct example {char c;     // 1字节int i;      // 4字节double d;   // 8字节
};

根据对齐规则,编译器可能会在char cint i之间插入3个填充字节,使得int类型的成员变量按照4字节对齐。同样地,在int idouble d之间可能会插入4个填充字节,使得double类型的成员变量按照8字节对齐。

因此,这个结构体的总大小可能是16字节。

需要注意的是,结构体对齐规则可能因编译器和编译选项的不同而有所不同,可以使用sizeof操作符来查看结构体的实际大小,也可以使用offsetof 计算结构体相较于起始位置的偏移量

四、例题

结构体怎么对齐? 为什么要进行内存对齐?

在C语言中,结构体是一种用户自定义的数据类型,它可以包含多个不同类型的数据成员。当结构体中的数据成员存储在内存中时,编译器会根据对齐规则对其进行对齐。

内存对齐是指将数据在内存中的地址对齐到特定的边界。对齐规则可以是不同的,但通常遵循以下原则:

  1. 数据类型对齐:基本数据类型如intfloat等有固定的对齐要求,通常是按照类型大小对齐。比如,int通常是按照4字节对齐,float按照4字节对齐。

  2. 结构体对齐:结构体的对齐方式是基于其最大成员的对齐要求。结构体的对齐要求是成员中对齐要求最高的,即按照最大成员的对齐要求进行对齐。不会计算结构体内存空间的可以看这篇文章——C语言从入门到实战——结构体与位段

内存对齐的目的主要有以下几点:

  1. 提高存取效率:对齐后的数据在读取和存储时速度更快,因为对齐的数据可以直接读到正确的内存地址,而非对不齐的数据可能会涉及额外的操作。

  2. 优化缓存性能:计算机内存通常按块存储,以缓存行为单位。对齐可以保证数据成员在同一缓存行中,减少缓存行的读取次数,提高缓存命中率。

  3. 兼容其他系统:在跨平台开发中,不同的硬件和操作系统可能对内存对齐有不同的要求。通过对齐,可以确保结构体在不同的系统上具有相同的内存布局,提高代码的可移植性。

需要注意的是,内存对齐可能会导致结构体的大小增加,因为编译器在成员之间插入填充字节以满足对齐要求。可以使用编译器的指令或者预处理指令来调整对齐方式,以优化内存使用。

如何让结构体按照指定的对齐参数进行对齐?能否按照3、4、5即任意字节对齐?

可以看下这篇文章C语言从入门到实战——结构体与位段

在C语言中,可以使用预处理指令#pragma pack(n)来指定对齐参数。n是对齐的字节数,可以是任意整数。

#pragma pack(3)
struct MyStruct {// 结构体成员
};

上述代码表示将MyStruct结构体按照3字节对齐。

但是,C标准并没有规定任意字节对齐的方式。通常情况下,对齐参数是2的幂次方。如果需要非2的幂次方的对齐参数,则需要使用特定的编译器扩展或者特定的平台相关特性。

请注意,在设置自定义的对齐参数时,可能会导致不同平台上的兼容性问题,因为结构体的对齐方式由编译器和平台决定。

什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景

C语言从入门到实战——数据在内存中的存储方式

大小端(Endianness)是一种描述数据存储方式的概念,用于表示一个多字节数据在内存中的存储顺序。在计算机系统中,多字节数据通常被分为若干个字节,而字节是由多个二进制位组成的。在大小端表示法中,主要考虑的是多字节数据的高位和低位的存储顺序。

大端(存储)模式:是指数据的低位字节内容保存在内存的高地址处,而数据的高位字节内容,保存在内存的低地址处。

小端(存储)模式:是指数据的低位字节内容保存在内存的低地址处,而数据的高位字节内容,保存在内存的高地址处。

为了测试某台机器是大端还是小端,可以通过以下方法之一:

  1. 使用C/C++等编程语言来测试,通过使用联合体(union)的方式来将一个整型数据与一个字符数组关联起来,并检查字符数组的存储顺序。如果数组的第一个字节是最低有效字节,则表示该机器是小端;如果数组的第一个字节是最高有效字节,则表示该机器是大端。

通过使用联合体(union)来将一个整型数据与一个字符数组关联起来,可以检查机器的字节序(即是小端还是大端)。

以下是使用C语言来实现的示例代码:

#include <stdio.h>// 定义一个联合体,整型数据与字符数组共用同一块内存空间
union Data {int i;char c[sizeof(int)];
};int main() {union Data data;// 将整型数据赋值data.i = 1;// 判断字节序if (data.c[0] == 1) {printf("This machine is little-endian.\n");} else {printf("This machine is big-endian.\n");}return 0;
}

运行以上代码时,将会输出机器的字节序信息。如果输出" This machine is little-endian.",表示该机器是小端;如果输出" This machine is big-endian.",表示该机器是大端。

注意:上述代码假设sizeof(int)等于4字节,如果在不同的机器上运行,可能会得到不同的结果,因为不同的机器有不同的字节序。

除此之外我们还可以使用指针来判断

#include <iostream>using namespace std;int main() {int num = 1;char *ptr = (char*)&num;if (*ptr == 1) {cout << "Little Endian" << endl;} else {cout << "Big Endian" << endl;}return 0;
}
  1. 使用系统命令或工具来查看机器的字节序。例如,在Linux系统下可以使用以下命令:
$ lscpu | grep "Byte Order"

如果输出结果是 "Little Endian",则表示该机器是小端;如果输出结果是 "Big Endian",则表示该机器是大端。

在某些场景中,需要考虑大小端的情况,例如在网络传输中,如果通信双方使用的字节序不同,就需要进行字节序的转换。在跨平台数据传输或者数据持久化存储时,也需要考虑大小端的问题。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/797552.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

知识图谱基本概念:数据、信息和知识

目录 前言1 数据&#xff1a;信息的基础1.1 数据的定义1.2 数据的重要性1.3 数据的例子1.4 数据的处理1.5 数据分析 2 信息&#xff1a;知识的基础2.1 信息的本质2.2 信息的转化过程2.3 信息的特点2.4 信息的示例 3 知识&#xff1a;智慧的体现3.1 知识的本质3.2 知识的形成过程…

【数据结构】红黑树详解

目录 前言&#xff1a; 红黑树的概念&#xff1a; 红黑树的性质: 红黑树节点的定义&#xff1a; 红黑树的插入&#xff1a; 情况1&#xff1a;cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;u存在且为红 情况2&#xff1a;cur为红&#xff0c;p为红&#xff0c…

C++从入门到精通——类的作用域及类的实例化

类的作用域及类的实例化 前言一、类的作用域二、类的实例化引例类是对对象进行描述的示例 一个类可以实例化出多个对象示例 示例 前言 类的作用域是指类中定义的变量和方法的可见性和可访问性范围。在类的内部&#xff0c;所有成员&#xff08;包括属性和方法&#xff09;都具…

GIT版本管理使用示例

一、创建好远程代码仓库后&#xff0c;复制远程仓库的地址 二、新建一个文件夹&#xff0c;在文件夹里打开Git Bash Here 三、输入git clone 远程仓库地址&#xff0c;仓库就初始化完成了 四、新建一个文本文件&#xff0c;假设这是我们开发的代码 五、打开文本&#xff0c;假设…

小秦网站部署上线

叮&#xff5e;您有一份消息&#xff0c;请注意查收&#xff01; 小秦个人网站终于上线了&#xff1a; 网站主要有&#xff1a;免费听歌、看小姐姐、AI女友、留言板等功能&#xff0c;建议收藏、收藏、再收藏、重要事情说三遍&#xff01;&#xff01;&#xff01; 网站&#x…

java实现运行脚本文件

在最近的项目中&#xff0c;有一个需求是前端传给我一个脚本文件&#xff0c;然后我需要运行脚本文件后将结果进行返回&#xff0c;那接下来就让我们看看是怎么做的吧&#xff01; public R runScripts(Integer id) {ScriptsInfo scriptsInfo this.baseMapper.selectById(id);…

工业4g路由器联网后迅速掉线是什么原因?

工业4G路由器连接上网后迅速掉线可能是由多种因素造成的。以下是一些建议的检查和解决步骤&#xff1a; 1、信号问题&#xff1a; 信号强度&#xff1a;检查工业路由器信号强度指示灯&#xff0c;如果信号弱&#xff0c;尝试移动路由器位置或添加外部天线来增强信号。 网络拥…

求m和n的最大公约数(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int remainder 1;int m 0;int n 0;int middle 0;//提示用户&#xff1b;printf("请输入整数m和n的值&#xff…

基于 OpenHarmony compress 三方件使用说明

关于 提供了一个轻量级的图像压缩库。将允许您将大照片压缩成小 尺寸的照片&#xff0c;图像质量损失或可以忽略不计 compress 的依赖添加 为你的应用添加 compress-debug.har。将 compress-debug.har 复制到 entry\libs 目录下即可&#xff08;由于 build.gradle 中已经依赖…

TopOn x Google Admob 自动创建广告源功能上线,支持一键添加广告单元 | TopOn产品速递

合作官宣 TopOn 正式成为亚太地区首家支持自动创建Admob bidding广告源的聚合平台。目前&#xff0c;在TopOn后台添加Admob广告平台&#xff0c;您只需要重新授权Google账号&#xff0c;即可开通自动创建功能。此前&#xff0c;TopOn 已在24年2月6日官方聚合支持Google biddin…

飞书文档如何在不同账号间迁移

今天由于个人需要新建了一个飞书账号&#xff0c;遇到个需求就是需要把老帐号里面的文档迁移到新的账号里面。在网上搜了一通&#xff0c;发现关于此的内容似乎不多&#xff0c;只好自己动手解决&#xff0c;记录一下过程以便分享&#xff0c;主要有以下几个步骤。 1. 添加新账…

python打印杨辉三角形

杨辉三角形&#xff0c;这个在国外被叫做帕斯卡三角形&#xff0c;中华文明为何立于世界之颠&#xff0c;这个就是最好的证明&#xff0c;古人的杨辉至少是这个帕斯卡的鼻祖辈&#xff0c;比帕某早了393年发现&#xff0c;那时候可没有知识产权概率&#xff0c;不然就是妥妥的侵…

JavaEE 初阶篇-深入了解线程池(线程池创建、线程池如何处理任务)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 线程池概述 1.1 线程池的优点 1.2 不使用线程池的问题 1.3 线程池的工作原理图 1.4 如何创建线程池&#xff1f; 2.0 通过 ThreadPoolExecutor 类自定义创建线程…

撸代码时,有哪些习惯一定要坚持?

我从2011年开始做单片机开发&#xff0c;一直保持以下撸代码的习惯。 1.做好代码版本管理 有些人&#xff0c;喜欢一个程序干到底&#xff0c;直到实现全部的产品功能&#xff0c;我以前做51单片机的项目就是这样。 如果功能比较多的产品&#xff0c;我不建议这样做&#xff0…

如何搭建APP分发平台分发平台搭建教程

搭建一个APP分发平台可以帮助开发者更好地分发和管理他们的应用程序。下面是一个简要的教程&#xff0c;介绍如何搭建一个APP分发平台。 1.确定需求和功能&#xff1a;首先&#xff0c;确定你的APP分发平台的需求和功能。考虑以下几个方面&#xff1a; 用户注册和登录&#xff…

Anritsu MS9740B与MS9740A 光谱分析仪 的区别?

MS9740B与MS9740A的主要区别在于测量处理时间的缩短和对高速信号处理技术的应用。MS9740B在保持原有功能和性能的同时&#xff0c;将测量处理时间缩短了一半。这一点通过提高生产效率和减少测量及检查时间来实现&#xff0c;从而提高了光有源设备制造商的生产力。此外&#xff…

mid转MP3怎么转?一分钟搞定~

MIDI&#xff08;Musical Instrument Digital Interface&#xff09;文件格式的诞生可以追溯到上世纪80年代&#xff0c;音频技术迅速崛起。为了让不同音乐设备之间能够互相通信&#xff0c;MIDI格式成为了音乐的标准。它不同于常见的音频文件格式&#xff0c;不包含实际的声音…

浮点数在内存中的存储【详解】

浮点数在内存中的存储 浮点数存储规则小数点后数值的二进制转换float和double存储图示优化存储方案E不全为0或不全为1E全为0E全为1 浮点数存储规则 大家都知道整型数据是以补码的方式存放在内存中。以下几个概念是需要知道的&#xff1a; 原码&#xff0c;补码&#xff0c;反…

汇编语言:寻址方式在结构化数据访问中的应用——计算人均收入

有一年多没有在CSDN上发博文了。人的工作重心总是有转移的&#xff0c;庆幸一直在做着有意义的事。   今天的内容&#xff0c;是为汇编语言课程更新一个实验项目。      本方案修改自王爽编《汇编语言》第&#xff14;版P172“实验7寻址方式在结构化数据访问中的应用” …

探索未来游戏:生成式人工智能AI如何重塑你的游戏世界?

生成式人工智能&#xff08;Generative AI&#xff09;正以前所未有的速度改变着各行各业的运作模式。其中&#xff0c;游戏产业作为科技应用的前沿阵地&#xff0c;正经历着前所未有的变革。本文将探讨生成式人工智能如何重塑游戏产业&#xff0c;以及这一变革背后的深远影响。…