C++入门:类和对象(上)

类和对象重点解析

  • 1.类的定义
    • 1.类的访问限定符及封装
      • 1.C++实现封装的方式
      • 2.访问限定符
        • 注意
      • 3.封装
  • 2.类对象模型
    • 2.1类对象存储方式
    • 2.2类对象的大小
      • 2.2.1结构体内存对齐原则
      • 2.2.2为什么要内存对齐
  • 3.this指针
    • 3.1this指针的引出
    • 3.2this指针的特性
    • 3.3this指针的存储
    • 3.4this指针可以为空吗?

1.类的定义

1.类的访问限定符及封装

1.C++实现封装的方式

用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选。择性的将其接口提供给外部的用户使用。

2.访问限定符

public(公有),protect(保护),private(私有)

注意
1.public修饰的成员在类外可以直接被访问
2.protected和private修饰的成员在类外不能直接被访问
3.访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4.如果后面没有访问限定符,作用域就到 } 即类结束。
5.class的默认访问权限为private,struct为public(因为struct要兼容C)

3.封装

面向对象的三大特性:封装,继承,多态

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。

封装本质上是一种管理,让用户更方便使用类。
通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。

2.类对象模型

2.1类对象存储方式

我们知道在C++中类的实现只是一个模板,用类创建成员后才会分配空间。如果创建多个对象,而每一个成员的函数都是一样的,那么在创建变量时是每一个成员都会有类函数还是所有的成员共用一个函数呢?那么我们在计算一个类对象的大小时应不应该计算这些函数的大小呢?

存储方式:每个对象中只保存成员变量,成员函数存放在公共的代码段。

a5468091abde0dd8a86df0.png)

2.2类对象的大小

2.2.1结构体内存对齐原则

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

注意:没有成员变量的类默认是1字节,占位标识对象的存在

2.2.2为什么要内存对齐

class A
{
private:
	char c;
	int i;
}

假设有一个类,先表示出对齐和不对齐的内存中的存储形式。
在这里插入图片描述
假设有三种读取方式:
方式一(内存对齐时):按照对齐的方式读取:先读取char,然后丢弃三个二进制位,再直接从int的开始位置进行读取。
方式二(不内存对齐时):先读取char,然后从char的下一个位置,也就是和char连续存储的int的位置。
方式三:先读取char,然后将剩余的三个字节存起来,再读取int的剩下的字节,然后将这两部分拼接起来。

首先,计算机根据地址线的大小,来确定能给多少存储器进行编码,是按照整数倍来读取,而不是从任意位置进行读取。而如果选择读取多次再进行数据的拼接的话更加麻烦,相比之下,内存对齐时只需要按顺序读取再丢掉不需要的那部分即可。
即:内存对齐就是计算机在读取数据的时候,尽量可以一次取到完整的数据而不是要分很多次才能拿到完整的数据,而且分多次拿到的话还需要进行数据的拼接组合,这样就会更加麻烦了。

3.this指针

3.1this指针的引出

class Date
{ 
public:
 	void Init(int year, int month, int day)
 	{
 		_year = year;
 		_month = month;
 		_day = day;
 	}
 	void Print()
 	{
 		cout <<_year<< "-" <<_month << "-"<< _day <<endl;
 	}
private:
 	int _year;     // 年
 	int _month;    // 月
	int _day;      // 日
};
int main()
{
 	Date d1, d2;
 	d1.Init(2022,1,11);
 	d2.Init(2022, 1, 12);
 	d1.Print();
 	d2.Print();
 	return 0;
}

对于上面的Date类当我们在调用类的成员函数中,由于没有对于对象的区分,那么编译器是如何知道是哪个对象调用了它的函数从而执行对应的操作呢?
比如在打印时如何区分打印d1的信息还是打印d2的信息。

解决方案:

C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

3.2this指针的特性

1.this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
2.只能在“成员函数”的内部使用
3.this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。
4.this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递

3.3this指针的存储

不存储在堆上:堆上内存需要我们自己去申请。
不存储在对象内:我们在计算类对象大小时并没有将其算入在内。
不存储在常量区和静态区:没有static修饰,其也不是常量。

this指针是地址,它的作用为作为形参,其存储在栈空间上,但是有的编译器比如VS可能会存储在寄存器中,这样访问的时候比较快。

3.4this指针可以为空吗?

可以。在我们之前的理解中,认为所有的空指针配合上解引用操作符都会崩毁,但是在一些情况下并非如此。

观察下面两段代码:
代码一:

class A
{
public:
	void Print()
	{
		cout << "Print()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	(*p).PrintA();
	p->Print();
	return 0;
}
这段代码可以正确打印出结果,程序不会崩溃。

代码二:

class A
{
public:
	void PrintA()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	(*p).PrintA();
	p->PrintA();
	return 0;
}
这里仅仅和上面有打印函数的差别,但是程序会崩溃。

首先,有*或者->都不一定是解引用,解引用以后要有实际意义编译器才会解引用。
我们上面的(*p)和->本质是给成员函数传递this指针,确定是哪个对象调用的this指针,this指针作为形参传递过去。

代码一:我们只是将空的this指针传递过去,在函数内部并没有解引用,因此程序正常运行。

代码二:我们将空的this指针传递之后,由于需要打印成员变量,因此必须对于this指针解引用从而找到该变量,进而造成空指针的解引用。

汇编观察:
在这里插入图片描述

我们通过反汇编也可以观察到,在底层并没有先对指针解引用,而是通过p去调用对应的Print函数。

以上是本次所有内容,谢谢观看。

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

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

相关文章

Three.js 中的 OrbitControls 是一个用于控制相机围绕目标旋转以及缩放、平移等操作的控制器。

demo案例 Three.js 中的 OrbitControls 是一个用于控制相机围绕目标旋转以及缩放、平移等操作的控制器。下面是它的详细讲解&#xff1a; 构造函数: OrbitControls(object: Camera, domElement?: HTMLElement)object&#xff1a;THREE.Camera 实例&#xff0c;控制器将围绕…

Kafka快速入门及使用

入门 官网 简介 Kafka是一个分布式的流媒体平台应用&#xff1a; 消息系统日志收集用户行为追踪流式处理 特点 高吞吐量消息持久化高可靠性高扩展性 常用术语 Broker&#xff1a;集群中的服务器Zookeeper&#xff1a;服务管理Topic&#xff1a;主题&#xff0c;Kafka发…

Attention Is All You Need若如爱因斯坦的相对论,Transformer模型则堪称E=MC^2之等量公式

Transformer模型已经成为当前所有自然语言处理NLP的标配&#xff0c;如GPT&#xff0c;Bert&#xff0c;Sora&#xff0c;LLama&#xff0c;Grok等。假如《Attention Is All You Need》类比为爱因斯坦的侠义相对论&#xff0c;Transformer模型则堪称EMC^2之等量公式。 看过论文…

IDEA Android新建项目基础

title: IDEA Android基础开发 search: 2024-03-16 tags: “#JavaAndroid开发” 一、构建基本项目 在使用 IDEA 进行基础的Android 开发时&#xff0c;我们可以通过IDEA自带的新建项目功能进行Android应用开发基础架构的搭建&#xff0c;可以直接找到 File --> New --> …

数据库管理开发工具Navicat for MySQL Mac版下载

Navicat for MySQL&#xff08;Mac版&#xff09;是一款强大的数据库管理开发工具&#xff0c;专为MySQL设计。它提供直观的用户界面&#xff0c;支持数据建模、查询构建、数据传输等功能&#xff0c;帮助用户轻松管理数据库。其特点包括高效的数据处理能力、安全的数据传输机制…

【算法与数据结构】 C语言实现单链表队列详解

文章目录 &#x1f4dd;队列&#x1f320; 数据结构设计&#x1f309;初始化队列函数 &#x1f320;销毁队列函数&#x1f309;入队函数 &#x1f320;出队函数&#x1f309;获取队首元素函数 &#x1f320;获取队尾元素函数&#x1f309; 判断队列是否为空函数&#x1f309;获…

HTTPS:原理、使用方法及安全威胁

文章目录 一、HTTPS技术原理1.1 主要技术原理1.2 HTTPS的工作过程1.2.1 握手阶段1.2.2 数据传输阶段 1.3 HTTPS的安全性 二、HTTPS使用方法三、HTTPS安全威胁四、总结 HTTPS&#xff08;全称&#xff1a;Hyper Text Transfer Protocol over Secure Socket Layer&#xff09;&am…

ARM:按键中断

key_inc.c #include"key_inc.h"void key1_it_config(){//使能GPIOF外设时钟RCC->MP_AHB4ENSETR | (0x1<<5);//将PF9设置为输入模式GPIOF->MODER & (~(0x3<<18));//设置由PF9管脚产生EXTI9事件EXTI->EXTICR3 & (~(0XFF<<8));EXTI…

【HarmonyOS】ArkUI - 页面路由

一、概念 页面路由是指在应用程序中实现不同页面之间的跳转和数据传递。 案例&#xff1a;第一次使用某个购物应用&#xff0c;打开时肯定会是一个登录页&#xff0c;在登录成功以后&#xff0c;会跳转到首页&#xff0c;然后可能会去搜索&#xff0c;就会进入到搜索列表页&am…

掌握Python中re模块的正则表达式应用与技巧【第155篇—正则表达式】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 掌握Python中re模块的正则表达式应用与技巧 Python 中的 re 模块是用于处理正则表达式的强…

[SAP MM] 名词专业术语解释

采购凭证 采购凭证通常是一种证明文件&#xff0c;用于记录和跟踪特定时间点的采购活动 采购凭证是指企业在采购物品或服务时所开立的一种凭证&#xff0c;用于记录采购的信息和流程 采购凭证通常包括采购申请、采购订单、采购合同等&#xff0c;其中采购订单是最常用的采购…

PCB中常用电子器件封装学习——【一网打尽】

‘ 上图是这个世界上大概所有的封装种类&#xff0c;当然我们日常硬件电路设计肯定用不到这么多&#xff0c;接下来我将介绍几种工程上常用的封装&#xff0c;配以图片方便大家理解学习。在电子器件选型的时候&#xff0c;避免选择到一些非常难以焊接的封装电子器件。

Acrobat Pro DC ----专业PDF编辑与管理

Acrobat Pro DC 2023是一款功能强大的PDF处理软件&#xff0c;它提供了丰富的编辑工具&#xff0c;支持创建、编辑、合并、分割PDF文件&#xff0c;以及高质量的PDF到其他格式的转换功能。同时&#xff0c;该软件集成了最新的OCR技术&#xff0c;可将扫描文档或图片转换成可编辑…

Godot 学习笔记(5):彻底的项目工程化,解决GodotProjectDir is null+工程化范例

文章目录 前言GodotProjectDir is null解决方法解决警告问题根本解决代码问题测试引用其实其它库的输出路径无所谓。 工程化范例环境命名规范Nuget项目结构架构代码ISceneModelIOC服务 测试GD_Extension 通用扩展TestUtils GD_ProgramTestServiceMainSceneModel Godot对应的脚本…

mac 解决随机出现的蓝色框

macbookair为什么打字的时候按空格键会出现蓝色框? - 知乎

t-rex2开放集目标检测

论文链接&#xff1a;http://arxiv.org/abs/2403.14610v1 项目链接&#xff1a;https://github.com/IDEA-Research/T-Rex 这篇文章的工作是基于t-rex1的工作继续做的&#xff0c;核心亮点&#xff1a; 是支持图片/文本两种模态的prompt进行输入&#xff0c;甚至进一步利用两…

配置git公钥

电脑重置重新配置公钥记录一下供自己观看 打开git bash 输入生成ssh公钥命令 ssh-keygen -t rsa -C your-email 一直回车直到出现 输入查看公钥命令 cat ~/.ssh/id_rsa.pub 复制公钥&#xff0c;打开git设置&#xff0c;找到ssh公钥添加(标题随便命名) 配置完后就可以正常使…

【DataWhale学习】灵境Agent开发——Agent介绍

【DataWhale学习】灵境Agent开发——Agent介绍 ​ 这次我参加了 DataWhale 的灵境Agent开发者训练营&#xff0c;第一次开发了一款属于自己的Agent&#xff0c;整体体验下来&#xff0c;操作还是非常方便的。灵境Agent和Coze上面创建的bot差不多&#xff0c;零代码开发可以仅仅…

QT常见布局器使用

布局简介 为什么要布局&#xff1f;通过布局拖动不影响鼠标拖动窗口的效果等优点.QT设计器布局比较固定&#xff0c;不方便后期修改和维护&#xff1b;在Qt里面布局分为四个大类 &#xff1a; 盒子布局&#xff1a;QBoxLayout 网格布局&#xff1a;QGridLayout 表单布局&am…

双指针(滑动窗口)-算法刷题

一.移动零&#xff08;. - 力扣&#xff08;LeetCode&#xff09;&#xff09; 算法思想 &#xff1a; 设置两个指针left,right&#xff0c;将数组分为三块[0,left]为不为0的元素&#xff0c;[left1,right-1]为0元素&#xff0c;[right,num.size()-1]为未扫描的区域&#xff0c…