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",则表示该机器是大端。

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


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

设计模式总结-适配器模式

适配器模式 模式动机模式定义模式结构适配器模式实例与解析实例一&#xff1a;仿生机器人实例二&#xff1a;加密适配器 总结 模式动机 在软件开发中采用类似于电源适配器的设计和编码技巧被称为适配器模式。 通常情况下&#xff0c;客户端可以通过目标类的接口访问它所提供的…

【PLC+Python】上位机通过snap7实现与西门子PLC通讯并用Tkinter可视化——(2)Python通讯和可视化

一 背景说明 计划通过西门子 S7-1200&#xff08;CPU 1212C-DCDCDC&#xff09;&#xff0c;进行PLC与设备间的数据监控。但 TIA Portal V15.1 的交互数据非专业人员很难一目了然&#xff0c;又不想专门购买西门子的可编程屏幕&#xff0c;所以拟采用 python-snap7 模块实现上位…

MQTT 5.0 报文解析 01:CONNECT 与 CONNACK

在 MQTT 5.0 报文介绍 中&#xff0c;我们介绍了 MQTT 报文由固定报头、可变报头和有效载荷三个部分组成&#xff0c;以及可变字节整数、属性这类 MQTT 报文中的通用概念。现在&#xff0c;我们将按照实际的用途来进一步介绍各个类型的报文的组成。首先&#xff0c;我们将专注于…

初识Java中的NIO

1.概述 Java NIO 全称java non-blocking IO &#xff0c;是指 JDK 提供的新 API。从 JDK1.4 开始&#xff0c;Java 提供了一系列改进的输入/输出新特性&#xff0c;被统称为 NIO(即 New IO)&#xff0c;是同步非阻塞的。NIO采用内存映射文件的方式来处理输入输出&#xff0c;NI…

电池UN38.3测试电池模组蓄电池检测报告出具

UN38.3运输报告规定了以下类型的电池&#xff1a; 1. 锂金属电池&#xff1a;包括锂金属氧化物电池&#xff08;如锂锰电池、锂铁电池、锂钴电池&#xff09;&#xff0c;锂-硫电池等。 2. 锂离子电池&#xff1a;包括锂聚合物电池、锂离子聚合物电池、锂离子含水电池等。 3.…

软考-系统集成项目管理中级-新一代信息技术

本章历年考题分值统计 本章重点常考知识点汇总清单(掌握部分可直接理解记忆) 本章历年考题及答案解析 32、2019 年上半年第 23 题 云计算通过网络提供可动态伸缩的廉价计算能力&#xff0c;(23)不属于云计算的特点。 A.虚拟化 B.高可扩展性 C.按需服务 D.优化本地存储 【参考…

记录一个C语言基础错误——scanf()输入!

今天犯了一个很傻的问题&#xff0c;记录一下。 Lint’Code 题目&#xff1a; 错误代码 #include <stdio.h>int function(int a, int b, int c, int x, int y) {// Write your code hereprintf("In function: %d\n", x y);x - y;return (a * (x y) * (x y…

深圳MES系统服务商

盈致MES系统是一款专业的制造执行系统&#xff0c;专注于为企业提供全面的生产管理解决方案。该系统涵盖了制造数据管理、计划排程管理、生产调度管理、库存管理、质量管理等功能模块&#xff0c;能够帮助企业实现生产过程的数字化、智能化和精益化。 盈致MES系统具有以下特点和…

openharmony launcher 调研笔记(01)数据初始化

最近在看launcher&#xff0c;把自己调研的点做个笔记&#xff0c;持续修改更新中&#xff0c;个人笔记酌情参考。 初始化MainAbility ● common 等 包以 三方库形式 被引入使用 在每个包中的oh-package.json5 文件有配置 { "devDependencies": {}, "n…

宏的使用(C语言详解)

在写一个代码生成可执行文件的过程需要经过编译和链接&#xff0c;编译又要经过三部&#xff1a;预处理&#xff0c;编译&#xff0c;汇编。 #define定义的变量和宏就是在预处理阶段会处理的。 一个简单的宏定义&#xff1a; #include<stdio.h>; #define Max(a,b) a>…

如何利用义乌购API实现用户个性化推荐及商品详情 API 返回值说明

用户个性化推荐 利用义乌购API实现用户个性化推荐是一个涉及多个步骤的过程&#xff0c;主要包括数据收集、用户画像构建、推荐算法选择与实施以及推荐结果的展示与反馈。以下是一个大致的流程和步骤说明&#xff1a; 一、数据收集&#xff1a; 1.用户行为数据&#xff1a;收…

如何理解单片机 pwm 控制的基本原理?

单片机PWM&#xff08;脉宽调制&#xff09;控制的基本原理&#xff0c;简而言之&#xff0c;就是通过改变脉冲信号的宽度&#xff08;占空比&#xff09;来控制模拟电路。这涉及到单片机生成一系列脉冲信号&#xff0c;每个脉冲信号的高电平持续时间和整个周期的比值&#xff…

桌面便签电脑版哪个好?好用便签是哪款

在快节奏的现代生活中&#xff0c;桌面便签软件成为了我们不可或缺的助手。它们轻便、灵活&#xff0c;能够随时记录重要事项&#xff0c;提醒我们按时完成各项任务。面对市面上众多的便签软件&#xff0c;选择一款既实用又好用的便签显得尤为重要。经过深入体验&#xff0c;我…

C++ | Leetcode C++题解之第12题整数转罗马数字

题目&#xff1a; 题解&#xff1a; const string thousands[] {"", "M", "MM", "MMM"}; const string hundreds[] {"", "C", "CC", "CCC", "CD", "D", "DC&qu…

【Angular性能优化】项目8版本加载速度缓慢、白屏时间、首页渲染性能优化方案

前言 随着业务的代码一点点增加,加上Angular的项目本身就比 vue、react 的重一些,随之而来的启动速度,更改文件后编译速度,以及打包速度也会变慢,于是乎想着优化下我们的项目。 本文章主要说的是 : 打包Angular项目的一些配置,性能优化方面的方案打包后,用户进入页面…

vue vue3 手写 动态加载组件

效果展示 一、需求背景&#xff1a; # vue3 项目涉及很多图表加载、表格加载 #考虑手写一个动态加载组件 二、实现思路 通过一个加载状态变量&#xff0c;通过v-if判断&#xff0c;加载状态的变量等于哪一个&#xff0c;动态加载组件内部就显示的哪一块组件。 三、实现效果…

Coursera上托福专项课程03:TOEFL Test-Taking Strategies 学习笔记(完结)

TOEFL Preparation Specialization Specialization Certificate TOEFL Test-Taking Strategies Course Certificate 本文是学习 TOEFL Test-Taking Strategies 这门课的学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。 文章目录 TOEFL Preparation SpecializationTOEF…

《web应用技术》第二次课后练习

练习目的&#xff1a; 1、form表单值的获取 2、mysql数据库及表的建立&#xff08;参见视频&#xff09; 3、maven项目的建立&#xff08;参见视频&#xff09; 4、使用jdbc进行数据库的增删改查操作。&#xff08;参见源代码&#xff09; 具体如下&#xff1a; 1、继续理…

以Kotti项目为例使用pytest测试项目

在维护和构建大型项目时&#xff0c;单独一个一个手工测试代码已经不适用了&#xff0c;这时候就要用专门的测试框架进行测试。让我们以Kotti项目为例&#xff0c;用pytest这个测试框架进行实践测试吧。 使用python3.10 Ubuntu 系统 准备工作 下载和安装kotti库 pip install…

并查集python实现及题目练习

文章目录 1. 并查集概念1.1 理解并查集&#xff1a;简介与应用场景1.2 Python 实现并查集及优化策略1.3 扁平化栈实现1.4 分析并查集的时间复杂度 2. 情侣牵手3. 相似字符串4. 岛屿数量 如果想了解并查集基础推荐去看左程云大神的算法讲解&#xff0c;非常不错&#xff0c;b站和…