【C++】总结3

news2025/4/6 0:53:19

文章目录

  • 1.类的访问限定符
  • 2.封装
  • 3.类对象的存储方式
  • 4.为什么要进行内存对齐?结构体怎么对齐?
  • 5.如何让结构体按照指定的对齐参数进行对齐
  • 6.如何知道结构体中某个成员相对于结构体起始位置的偏移量
  • 7.C++有哪几种构造函数
  • 8.类的六个默认成员函数
  • 9.构造函数
  • 10.析构函数
  • 11.拷贝构造函数
  • 12.运算符重载
  • 13.浅拷贝和深拷贝

1.类的访问限定符

  • 访问限定符:public、protected、private

  • public修饰的成员在类外可以直接被访问

  • protected和private修饰的成员在类外不能直接被访问(此处protected和private类似)

  • 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止

  • class的默认访问权限为private,struct为public(因为struct要兼容C)

2.封装

  • C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部用户使用。
  • 封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。封装可以看作是将数据和操作包装在一个黑盒子中,只暴露出必要的接口,而隐藏了内部的实现细节
  • 封装是为了实现以下目标:数据隐藏、接口统一、降低耦合、代码重用

3.类对象的存储方式

  • 假设对象中包含类的各个成员,这样就有缺陷:每个对象中只有成员变量是不同的,但是调用同一份函数,如果按照这种方式存储,当一个类创建多个对象时,每个对象都会保存一份代码,相同代码保存多次,浪费空间。于是我们就有了这种存储方式:只保存成员变量,成员函数存放在公共的代码段。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pteuSp4r-1690366651101)(C:\Users\姬新羽\AppData\Roaming\Typora\typora-user-images\image-20230726093605145.png)]

  • 总之,一个类的大小,实际即是该类中“成员变量”之和,也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类

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

  • 内存对齐是指将结构体的成员在内存中排列为一系列连续的块,并且要求成员的地址是其自身大小的整数倍。这样做的目的是为了优化内存访问速度和处理器的数据访问效率。

  • 内存对齐的原因和优势包括:

    • 性能优化:处理器通常在较对齐的内存地址上执行数据访问操作更快。

    • 移植性:内存对齐可以确保代码在不同平台上的行为一致性,避免因为数据对齐不一致而产生的错误或异常。

    • 结构体大小优化:有些编译器会对结构体进行优化,通过进行内存对齐来减少空洞和填充,从而减小结构体的大小。

  • 常见的对齐规则

    • 以成员的自身大小为单位,确保每个成员的起始地址是其自身大小的整数倍

    • 第一个成员在与结构体偏移量为0的地址处

    • 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的对齐数为8

    • 结构体总大小:最大对齐数(所有变量类型最大者与默认对其参数取最小的)的整数倍

    • 如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

例如,假设有以下结构体:

struct MyStruct {
    char a;
    int b;
    double c;
};

按4字节对齐:

a - 1字节
(3字节填充)
b - 4字节
c - 8字节

5.如何让结构体按照指定的对齐参数进行对齐

  • 在 Visual Studio C++ 编译器中,可以使用 #pragma pack(n) 指令来指定结构体的对齐方式,其中 n 表示对齐的字节数。在指定的结构体之后的代码中,都会按照指定的对齐方式进行对齐,直到遇到 #pragma pack() 恢复默认对齐方式。
  #pragma pack(8) // 指定后续结构体按照 8 字节对齐
  
  struct MyStruct {
      char a;
      int b;
      double c;
  };
  
  #pragma pack() // 恢复默认对齐方式

6.如何知道结构体中某个成员相对于结构体起始位置的偏移量

  • 可以使用 offsetof 宏来获取结构体中某个成员相对于结构体起始位置的偏移量。offsetof 宏定义在 <cstddef> 头文件中(在 C 中定义在 <stddef.h> 头文件中),它能够帮助我们在编译时获取结构体成员的偏移量。

  • offsetof 宏的使用方式如下:

  #include <cstddef>
  
  struct MyStruct {
      int a;
      double b;
      char c;
  };
  
  int main() {
      size_t offsetA = offsetof(MyStruct, a);
      size_t offsetB = offsetof(MyStruct, b);
      size_t offsetC = offsetof(MyStruct, c);
  
      std::cout << "Offset of 'a': " << offsetA << std::endl;
      std::cout << "Offset of 'b': " << offsetB << std::endl;
      std::cout << "Offset of 'c': " << offsetC << std::endl;
      
      cout << sizeof(MyStruct) << endl;
      return 0;
  }

输出结果:

  Offset of 'a': 0
  Offset of 'b': 8
  Offset of 'c': 16
  24

结构体的成员在内存中是按照定义的顺序存放的,偏移量是成员相对于结构体起始位置的字节偏移。

7.C++有哪几种构造函数

  • 默认构造函数
  • 初始化构造函数
  • 拷贝构造函数
  • 移动构造函数
  • 委托构造函数
  • 转换构造函数

8.类的六个默认成员函数

  • 任何一个类在我们自己不写的情况下,都会自动生成下面六个默认成员函数(包括空类)
  • 初始化和清理:
    • 构造函数主要完成初始化工作
    • 析构函数主要完成清理工作
  • 拷贝复制
    • 拷贝构造:用同类对象初始化创建对象
    • 赋值运算符重载:把一个对象赋值给另一个对象
  • 取地址重载
    • 主要是普通对象和const对象取地址(这两个很少会自己实现)

9.构造函数

  • 构造函数是特殊的成员函数,主要任务是初始化对象

  • 构造函数特征如下:

    • 函数名与类名相同
    • 无返回值
    • 对象实例化时编译器自动调用对应的构造函数
    • 构造函数可以重载
    • 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成
    • 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们未显式定义编译器默认生成的构造函数,都可以认为是默认成员函数
  • 关于编译器生成的默认成员函数的作用:在我们不实现构造函数的情况下,编译器会生成默认的构造函数,但是此时我们的成员变量依旧是随机值,那编译器生成的默认构造函数有什么作用呢?

    C++把类型分成内置类型(基本类型)和自定义类型。观察下面代码,编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数。

  class Time{
  public:
  	Time(){
  		cout << "Time()" << endl;
  		_hour = 0;
  		_minute = 0;
  		_second = 0;
  	}
  private:
  	int _hour;
  	int _minute;
  	int _second;
  };
  class Date{
  private:
  	// 基本类型(内置类型)
  	int _year;
  	int _month;
  	int _day;
  	// 自定义类型
  	Time _t;
  };
  int main(){
  	Date d;
  	return 0;
  }

10.析构函数

  • 析构函数:与构造函数功能相反,析构函数不是完成对象的销毁 ,局部对象销毁工作是由编译器完成的。对象在销毁时会自动调用析构函数,完成类的一些资源清理工作

  • 析构函数特征:

    • 析构函数名是在类名前加上字符~

    • 无参数无返回值

    • 一个类有且只有一个析构函数,若未显式定义,系统会自动生成默认的析构函数

    • 对象生命周期结束时,C++编译系统自动调用析构函数

    • 关于编译器自动生成的默认析构函数,对自定义类型成员调用它的析构函数

11.拷贝构造函数

  • 拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
  • 拷贝构造函数特征:
    • 拷贝构造函数是构造函数的一个重载形式。
    • 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
    • 若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷 贝,这种拷贝我们叫做浅拷贝,或者值拷贝。

12.运算符重载

  • C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数
  • 函数名字为:关键字operator后面接需要重载的运算符符号
  • 函数原型:返回值类型 operator操作符(参数列表)
  • 注意:
    • 重载操作符必须有一个类类型或者枚举类型的操作数
    • 用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义
    • 作为类成员的重载函数时,其形参看起来比操作数数目少1,成员函数的操作符有一个默认的形参this,限定为第一个形参
    • .*成员指针访问运算符、::作用域运算符、sizeof?:条件运算符、. 成员访问运算符 不能重载

13.浅拷贝和深拷贝

  • 浅拷贝是简单的将一个对象的数据成员的值赋值到另一个对象中。浅拷贝只复制指针的值,而不复制指针指向的内容 ,因此,原对象会和拷贝对象会指向同一块内存地址。如果原来的指针所指向的资源释放了,那么再释放浅拷贝的指针的资源就会出现错误。浅拷贝适用于简单的数据类型,以及不涉及资源管理的类对象

  • 深拷贝是在进行拷贝时,会为目标对象重新分配独立的内存,并复制源对象的内容到新分配的内存中,而不是简单的复制指针的值。这样两个对象完全独立,互不影响。深拷贝适用于包含指针成员的类对象,以及设计资源管理(例如动态内存分配、文件句柄等)的情况。

示例代码:

  class String{
  public:
  	String(const char* str = "\0")
  		//字符串常量要用常指针,要加const
  	{
  		m_data = (char*)malloc(strlen(str) + 1);//深拷贝
  		//开辟空间要考虑字符串结束标志\0,所以要加一
  		strcpy(m_data, str);
  		cout << m_data << " : " << &m_data << endl;
  	}
  
  	String(const String &s)
  	{
  		m_data = (char*)malloc(strlen(s.m_data) + 1);
  		strcpy(m_data, s.m_data);
  		cout << m_data << " : " << &m_data << endl;
  	}
  	~String()
  	{
  		free(m_data);
  	}
  private:
  	char *m_data = nullptr;
  };
  int main()
  {
  	String s("Hello");
  	String s1 = s;//拷贝构造
  	return 0;
  }

最后发现s和s1是独立的两个对象:

  Hello : 004FFE0C
  Hello : 004FFE00

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

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

相关文章

web-xss

HTML的< >&amp;&quot;©分别是<&#xff0c;>&#xff0c;&&#xff0c;"&#xff0c;©;的转义字符 XML只有5个转义符: < >&amp; &quot; &apos; HTTP请求中&#xff0c;Referer是header的一部分&#xff0c;当浏览器…

【防火墙】iptables防火墙(二)

1.写在命令行的备份和还原 2.把我们的规则配置在服务的文件当中&#xff0c;形成永久生效 iptables-save > /opt/ky30.bak iptables-restore < /opt/ky30.bak cat /etc/sysconfig/iptables 永久生效的配置文件 自定义链&#xff1a; 1.创建自定义链&#xff1a; i…

【数据结构】---时间复杂度与空间复杂度

时间复杂度与空间复杂度 1.&#x1f4c9; 时间复杂度&#x1f4cc;1.1 时间复杂度的概念1.2 大O的渐进表示法 &#x1f3f0;空间复杂度&#x1f4c3;例题分析1.案例&#xff08;常数阶&#xff09;2.案例&#xff08;线性阶&#xff09;3.案例&#xff1a;&#xff08;平方阶&a…

香港中文大学多媒体实验室——人工智能与计算机视觉的创新引擎

原创 | 文 BFT机器人 01 引言 香港中文大学多媒体实验室&#xff08;MultimediaLaboratory&#xff09;成立于2001年7月&#xff0c;是香港中文大学信息工程学系的重要组成部分。该实验室由汤晓鸥教授执导&#xff0c;是最早应用深度学习进行计算机视觉研究的华人团队之一。因…

Latex | 将MATLAB图并导入Latex中的方法

一、问题描述 用Latex时写paper时&#xff0c;要导入MATLAB生成的图进去 二、解决思路 &#xff08;1&#xff09;在MATLAB生成图片的窗口中&#xff0c;导出.eps矢量图 &#xff08;2&#xff09;把图上传到overleaf的目录 &#xff08;3&#xff09;在文中添加相应代码 三…

麒麟v10-coredns 启动失败

现象 在麒麟ARM芯片的机器上搭建k8s&#xff0c;其中的的一个组件cordons 发现启动失败&#xff0c;查看日志如下所示&#xff1a;No such device or address 问题分析 期初猜测kubelet与containerd的cgroupDriver驱动不一致导致。分别查看是一致的。没有问题。发现系统存在…

阿里云NVIDIA A100 GPU云服务器性能详解及租用费用

阿里云GPU服务器租用费用表包括包年包月、一个小时收费以及学生GPU服务器租用费用&#xff0c;阿里云GPU计算卡包括NVIDIA V100计算卡、T4计算卡、A10计算卡和A100计算卡&#xff0c;GPU云服务器gn6i可享受3折&#xff0c;阿里云百科分享阿里云GPU服务器租用表、GPU一个小时多少…

javafx拖拽图片实现

效果 代码 package cn.juhe.zjsb.test;import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.HBox; import javaf…

jmeter接口自动化测试工具在企业开展实际的操作

在企业使用jmeter开展实际的接口自动化测试工具&#xff0c;建议按如下操作流程&#xff0c; 可以使整个接口测试过程更规范&#xff0c;更有效。 接口自动化的流程&#xff1a; 1、获取到接口文档&#xff1a;swagger、word、excel ... 2、熟悉接口文档然后设计测试用例&am…

SAFe工具,SAFe规模化敏捷工具,SAFe实施流程,SAFe框架管理工具

​Leangoo领歌敏捷工具覆盖了敏捷项目研发全流程&#xff0c;包括小型团队敏捷开发&#xff0c;Scrum of Scrums大规模敏捷。 随着SAFe的越来越普及&#xff0c;Leangoo本次上线提供了完整的SAFe框架功能&#xff0c;包括&#xff1a;Program Backlog&#xff0c;PI规划&#…

Linux相关指令(上)

常见指令&#xff1a; 1 pwd&#xff1a;查看用户当前所在目录 以下面的路径为例&#xff1a; 2 ls&#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。 对于文件&#xff0c;将列出文件名以及其他信息 ls-l&#xff08;or ll&#xff09;&#xff1a;列…

插槽slot复习

1.认识插槽 ◼ 在开发中&#xff0c;我们会经常封装一个个可复用的组件&#xff1a;  前面我们会通过props传递给组件一些数据&#xff0c;让组件来进行展示&#xff1b;  但是为了让这个组件具备更强的通用性&#xff0c;我们不能将组件中的内容限制为固定的div、span等等…

学生公寓报修管理系统的设计与实现(论文+源码)_kaic

摘 要 随着科技的发展&#xff0c;信息化的管理手段早以在人们生活的各个方面取代了传统的管理手段&#xff0c;以先进管理理念为基础的现代化信息管理系统已经成为了许多机构的必备工具。在如今大学的校园里&#xff0c;有着许许多多的信息化管理系统&#xff0c;如图书管理系…

面试官:Redis 为什么变慢了?怎么解决?

一、Redis为什么变慢了 二、Redis如何优化 三、Redis变慢了排查步骤 一、Redis为什么变慢了 1.Redis真的变慢了吗&#xff1f; 对 Redis 进行基准性能测试 例如&#xff0c;我的机器配置比较低&#xff0c;当延迟为 2ms 时&#xff0c;我就认为 Redis 变慢了&#xff0c;…

Qt : day2

1. #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {qDebug() << this->size(); //获取当前页面尺寸this->setFixedSize(500, 600); //设置固定尺寸this->setWindowTitle("聊天框"); //设置窗口标题thi…

快速批量处理,高效添加水印的软件推荐

辛迪&#xff1a;嘿&#xff0c;你听说过加水印技术吗&#xff1f; 杰克&#xff1a;当然啦&#xff01;那是一种在图像或视频上添加标识的技术&#xff0c;对吧&#xff1f; 辛迪&#xff1a;没错&#xff01;加水印技术可以在作品上添加标识、文字、图像等&#xff0c;以保…

Python实现HBA混合蝙蝠智能算法优化XGBoost回归模型(XGBRegressor算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蝙蝠算法是2010年杨教授基于群体智能提出的启发式搜索算法&#xff0c;是一种搜索全局最优解的有效方法…

【计算机】磁盘基础知识

一、背景前言 今年2023年&#xff0c;已经是机械硬盘诞生的第67个年头了。作为存储数据的硬件设备&#xff0c;它的发展可谓历经了很多人的努力&#xff0c;在这个过程中也发现很多有意思的事情。通常在生活中&#xff0c;不太懂计算机的朋友们常把内存与硬盘的概念混淆&#…

怎么把图片压缩小一点?三招教会你压缩图片

在现如今的互联网时代&#xff0c;图片是我们日常生活中不可或缺的一部分&#xff0c;无论是在社交媒体上分享照片&#xff0c;还是在网站上发布图片&#xff0c;我们都希望图片能够加载得更快&#xff0c;占用更少的存储空间。因此&#xff0c;将图片压缩变得尤为重要&#xf…

C# 用队列实现栈

225 用队列实现栈 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void push(int x) 将元素 x 压入栈顶。 int pop() 移除并返…