【C++杂货铺】详解类和对象 [上]

                                        博主:代码菌@-CSDN博客

                                        专栏:C++杂货铺_代码菌@的博客-CSDN博客


目录

🌈前言🌈

📁 面向对象语言的特性

📁 类

 📂 概念

 📂 定义

📁 访问限定符

 📂分类

 📂 封装

📁 类的作用域

📁 类的实例化

📁 类的模型

📂 类的存储

📁 面试题

📁this指针(灰常重要)

 📂 this指针的引入

 📂 this指针的特性

 📂面试题

📁 总结


🌈前言🌈

        欢迎收看本期【C++杂货铺】,这期内容,我们将围绕C++中类和对象部分内容进行讲解,包括了 封装,类的概念,如何定义类和类的大小等内容,最后我们给出工作面试出的一道题目进行讲解。

        如果你想学习C++,或者刚学完C语言衔接C++,那么这篇文章将会非常有效的帮助你理解。

📁 面向对象语言的特性

        面向对象语言有三大特性:封装,继承,多态。在类和对象中,我们重点讲解一下,什么是封装。

        例如,我们使用电脑,用户只需要知道如何与鼠标,键盘等进行交互,而不需要知道机器内部CPU,内存等是如何工作的,厂商都将其隐藏起来,封装在机箱中,这就是封装的过程。而这个机箱就是 类。

📁 类

 📂 概念

        不知道你是否学习过C语言中的结构体struct,来存储不同类型的数据。类就是结构体的进阶版,类 中不仅可以定义变量(成员变量),还可以定义 函数(成员函数)。

 📂 定义

class className
{// 类体:由成员函数和成员变量组成 ...
};struct Name
{// 类体:由成员函数和成员变量组成...
}

        需要注意的是类,不仅可以是class,也可以是struct。class定义时{}后面有 ; ,这点需要注意。

        class为定义类的关键字,ClassName为类的名字,{}内为类的主体。

        类体中的内容称为类的成员:类中的变量称为类的属性或者成员变量;类中的函数称为类的方法或成员函数

        类的两种定义方式:

        1. 声明和定义都在类体中,需要注意的是:成员函数如果在类中定义,编译器可能会将其当做是内联函数处理。(如果不懂内联函数,可以参考下面这篇文章)

【C++杂货铺】三分钟彻底搞懂函数重载-CSDN博客

        下图中,public 和 private是限定操作符。

        2. 类的声明放在 .h 文件中, 成员函数定义在 .cpp文件中。

        一般情况是,在学习竞赛中使用第一种情况;工作过程,采用第二种。

        此外,还有一个约定俗成,就是成员变量一般以 _开头,也是为了方便区分。

📁 访问限定符

        什么是访问限定符呢,就是一种限制。例如,我们的电脑,对于一个小白,那就限制他只能使用鼠标键盘等操作,不允许触碰机器内部的元器件。鼠标键盘就是共有的,机器元器件就是私有的。

 📂分类

【 访问限定符说明 】:

1. public 修饰的成员在类外可以直接被访问。
2. protected private 修饰的成员在类外不能直接被访问 ( 此处 protected private 是类似的 )。
3. 访问权限 作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。
4. 如果后面没有访问限定符,作用域就到 } 即类结束。
5. class 的默认访问权限为 private struct public( 因为 struct 要兼容 C)。
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

        

        C++需要兼容C语言,所以C语言中的struct可以当成结构体来使用。另外C++中struct还可以用来定义类。和class一样,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。

(注意:在继承和模板参数列表位置也有区别,后续给大家介绍)

 📂 封装

        C++中实现封装的方式: 用类将对象的属性与方法结合在一起,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。

封装具有一下特性:

        1. C++中数据和方法都在类中

        2. 通过C++访问限定符对成员进行限制,可以访问在公有作用域下,不可以访问在私有作用域下。

        封装的本质是一种管理,让用户更加方便的使用类。

📁 类的作用域

        类定义了一个新的作用域,类的所有成员都在这个类中。在类体外定义成员时,需要使用 :: 来标明作用域操作符指明成员属于哪个类域。

class Person
{
public:void PrintPersonInfo();
private:char _name[20];char _gender[3];int  _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{cout << _name << " "<< _gender << " " << _age << endl;
}

📁 类的实例化

       用类 来创建对象的过程,叫做类的实例化。

1. 类是对对象进行描述的,是一个模型,限定了类有哪些成员,定义一个类并没有分配具体实际的内存空间来存储。

2. 类 可以实例化出多个对象,实例化的对象 占用实际的物理空间,存储成员变量。

📁 类的模型

        类中既有成员变量,又有成员函数,那么如何计算类的大小呢?

📂 类的存储

● 对象中包含类的各个成员

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

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

        目前,是采用第三种方法。也就是说,成员变量存在对象中,而成员函数存在代码区。因为大家想想,如果每个成员函数都存储一份相同的成员函数,会造成很大的空间浪费。

        求类的对象大小,就是看里面的成员变量。

// 类中既有成员变量,又有成员函数
class A1 {
public:void f1(){}
private:int _a;
};
// 类中仅有成员函数
class A2 {
public:void f2() {}
};
// 类中什么都没有---空类
class A3
{};
sizeof(A1) : ___4_ __    sizeof(A2) : ___1_ __     sizeof(A3) : ___1_ __
        这也说明,如果没有成员变量,类的大小为1Byte。
结论:一个类的大小,实际就是该类中 成员变量 之和,当然要注意内存对齐
注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。

📁 面试题

1. 结构体怎么对齐? 为什么要进行内存对齐?
        (1). 第一个成员在与结构体偏移量为 0 的地址处。
        (2). 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
        注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
        VS中默认的对齐数为8
        (3). 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数    倍。
        (4). 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
2. 如何让结构体按照指定的对齐参数进行对齐?能否按照3、4、5即任意字节对齐?
 #pragma pack( ~ )  这个预处理指令,可以改变编译器的默认对齐数。

📁this指针(灰常重要)

 📂 this指针的引入

        如果我们实例化两个相同类的对象A,B。同时调用成员函数初始化和打印这两个对象,如下。

class Date
{
private:int _year;int _month;int _day
public:void Init(int year,int month,int day){_yeaar = year;_month = month;_day = day;}void Print(){cout<<_year<<'/'<<_month<<'/'<<_day<<endl;}
}int main()
{Date A;A.Init(1,1,1);A.Print();Date B;B.Init(2,2,2);B.Print();
}

        编译器如何识别A和B呢?通过类的模型,我们知道,A和B的所调用的函数都是同一个,都是执行相同的指令,那编译器怎么识别year,month,day是A还是B的成员变量了。

        你会发现,谁调用了,就打印,赋值给谁的成员变量。

        这就引入了this指针的概念,隐含的this指针。所有的成员函数都隐藏一个形参,调用的地方,编译器也会处理。

 void Print(Date* const this)
{cout<<_year<<'/'<<_month<<'/'<<_day<<endl;
}A.Print(&A);

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

 📂 this指针的特性

        1. this指针的类型 类型 * const 。即在成员函数中,this1指针不能被修改指向。

        2. 在形参和实参的位置不能显示写。即你不能写this,这是编译器做的事,你做了,编译器会报错。

        3. this指针只能在成员函数中内部使用。

        4. this指针的本质是 成员函数的形参,当对象调用成员函数时,将对象地址作为实参传递给this这个形参,所以对象不存储this指针

        5. this指针是成员函数第一个隐含的指针形参,一般情况下由编译器通过ecx寄存器自动传递,不需要用户传递。

 📂面试题

this指针存在在哪里?B

A. 堆                B. 栈        C. 静态区        D. 常量区          E. 对象里面        

解析:

        首先排除E,因为对象实例化后,只存储成员变量,这是在类的模型中讲解的。

        其次,排除常量区,cosnt修饰的常变量本质上还是变量。

        然后,排除静态区,静态区只存储 static静态变量和全局变量。

        最后,排除堆,堆是程序员自己开辟管理的空间。

this指针可以为空吗:可以,只要不在成员函数中解引用。

        我么创建一个类的空指针,空指针作为实参传递给形参。

        ( mov的意思就是数据赋值,lea的意思就是取地址。)

        

        下面为案例,成员函数不存储在对象中,所以A->Print不是解引用,编译器会识别成Date::Print即通过A的类找到Print这个成员函数。其他成员函数也是同理。

① 在成员函数不解引用this指针。

class Date
{
private:int _year;int _month;int _day
public:void Init(int year,int month,int day){_yeaar = year;_month = month;_day = day;}void Print(){cout<<_year<<'/'<<_month<<'/'<<_day<<endl;}
}
int main()
{Date* A = nullptr;
A->Print();
}

        上面代码,会将A的值传递给this指针,但在Print中并没有解引用空指针,所以程序正常运行。

② 如果this指针为空,在成员函数解引用this指针。会发生运行错误。

class Date
{
private:int _year;int _month;int _day
public:void Init(int year,int month,int day){_yeaar = year;_month = month;_day = day;}void Print(){cout<<_year<<'/'<<_month<<'/'<<_day<<endl;}
}int main()
{Date* A = nullptr;
A->Init();
}

        上面代码,会将A的值传递给this指针,但在Init中解引用空指针,所以程序运行错误。

        总结一下,可以定义了一个类的指针为空指针,通过空指针,可以找到类的成员函数,此时,并不是空指针的解引用,此外,空指针将赋值给this指针。

        this指针可以为空,但在成员函数中解引用this指针会运行错误。

📁 总结

        总结,类就类似于struct结构体,不过可以再内部定义成员函数。

        通过学习类,了解什么是封装,即通过类将对象的属性和方法结合在一起,通过访问限定符有选择的接口提供给外部用户使用。封装的本质就是一种管控。

        当然这只是类的初窥门槛,之后的文章将逐渐揭开类的神秘面纱。

        如果这篇文章对你有所收获,欢迎点赞,评论,收藏。Thanks♪(・ω・)ノ

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

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

相关文章

CMake 完整入门教程(一)

1 前言 每一次学习新东西都是很有乐趣的&#xff0c;虽然刚开始会花费时间用来学习&#xff0c;但是实践证明&#xff0c;虽然学习新东西可能会花费一些时间&#xff0c;但是它们带来的好处会远远超过这些花费的时间。学习新东西是值得的&#xff0c;也是很有乐趣的。 网络上…

【K8S 云原生】K8S的图形化工具——Rancher

目录 一、rancher概述 1、rancher概念 2、rancher和K8S的区别&#xff1a; 二、实验 1、安装部署 2、给集群添加监控&#xff1a; 3、创建命名空间&#xff1a; 4、创建deployment&#xff1a; 5、创建service&#xff1a; 6、创建ingress&#xff1a; 7、创建hpa 8…

基于高精度YOLOv8开发构建公共场景下行人人员姿态估计分析识别系统

姿态估计&#xff08;PoseEstimation&#xff09;在我们前面的相关项目中涉及到的并不多&#xff0c;CV数据场景下主要还是以目标检测、图像识别和分割居多&#xff0c;最近正好项目中在使用YOLO系列最新的模型开发项目&#xff0c;就想着抽时间基于YOLOv8也开发构建实现人体姿…

[UI5 常用控件] 02.Title,Link,Label

文章目录 前言1. Title1.1 结合Panel1.2 结合Table1.3 Title里嵌套Link 2. Link3. Label3.1 普通用法3.2 在Form里使用 前言 本章节记录常用控件Title,Link,Label。 其路径分别是&#xff1a; sap.m.Titlesap.m.Linksap.m.Label 1. Title Title可以结合其他控件一起使用 1.…

总结红包雨项目的所有代码,包括添加图片,分享按钮,红包雨,用户是否有抽奖逻辑判断

整体实现效果: 需要用的图片: html: <body><div id"app"><!-- <div class"share-box"><img src"./share_box.png" alt"share-button"></div> --><!-- img图片 --><div class"gif-…

JVM基础知识汇总篇

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…

翻译: GPT-4 with Vision 升级 Streamlit 应用程序的 7 种方式一

随着 OpenAI 在多模态方面的最新进展&#xff0c;想象一下将这种能力与视觉理解相结合。 现在&#xff0c;您可以在 Streamlit 应用程序中使用 GPT-4 和 Vision&#xff0c;以&#xff1a; 从草图和静态图像构建 Streamlit 应用程序。帮助你优化应用的用户体验&#xff0c;包…

《合成孔径雷达成像算法与实现》Figure5.18

clc clear close all距离向参数 R_eta_c 20e3; % 景中心斜距 Tr 25e-6; % 发射脉冲时宽 Kr 0.25e12; % 距离向调频率 Fr 7.5e6; % 距离向采样率 Nrg 256; % 距离线采样点数 Bw abs(Kr*Tr); …

.NET绿色开源一键自动化下载、安装、激活Office的利器

前言 今天分享一款.NET开源、绿色、安全、无毒的支持一键自动化下载、安装、激活Microsoft Office的利器&#xff1a;LKY_OfficeTools。 工具介绍 一键自动化下载、安装、激活 Microsoft Office 的利器。绿色、开源、安全、无毒。 目前包含的功能&#xff1a; 一键快速下载、…

【机器学习300问】16、逻辑回归模型实现分类的原理?

在上一篇文章中&#xff0c;我初步介绍了什么是逻辑回归模型&#xff0c;从它能解决什么问题开始介绍&#xff0c;并讲到了它长什么样子的。如果有需要的小伙伴可以回顾一下&#xff0c;链接我放在下面啦&#xff1a; 【机器学习300问】15、什么是…

C#,计算几何,二维贝塞尔拟合曲线(Bézier Curve)参数点的计算代码

Pierre Bzier Bzier 算法用于曲线的拟合与插值。 插值是一个或一组函数计算的数值完全经过给定的点。 拟合是一个或一组函数计算的数值尽量路过给定的点。 这里给出 二维 Bzier 曲线拟合的参数点计算代码。 区别于另外一种读音接近的贝塞耳插值算法&#xff08;Bessels int…

【CAD全套教程】第1阶段 CAD软件教程 002+003基础界面设置

002基础界面设置 1.切换界面至AutoCAD经典界面 方式一&#xff1a;任务栏点击后直接选择 方式二&#xff1a;右下角点击齿轮图标&#xff08;切换工作空间&#xff09;后直接选择 界面图 2.AutoCAD常用命令 工具栏右键单击&#xff0c;选择AutoCAD 3.命令提示行 最下方&#xf…

【Docker】实现JMeter分布式压测

一个JMeter实例可能无法产生足够的负载来对你的应用程序进行压力测试。如本网站所示&#xff0c;一个JMeter实例将能够控制许多其他的远程JMeter实例&#xff0c;并对你的应用程序产生更大的负载。JMeter使用Java RMI[远程方法调用]来与分布式网络中的对象进行交互。JMeter主站…

【前端web入门第二天】01 html语法实现列表与表格_合并单元格

html语法实现列表与表格 文章目录: 1.列表 1.1 无序列表1.2 有序列表1.3 定义列表 2.表格 2.1 表格基本结构2.2 表格结构标签2.3 合并单元格 写在最前,第二天学习目标: 列表 表格 表单 元素为嵌套关系 1.列表 作用:布局内容排列整齐的区域。 列表分类:无序列表、有序列表…

数字IC实践项目(8)—CNN加速器(ASIC_Flow;付费项目补充)

数字IC实践项目&#xff08;8&#xff09;—CNN加速器&#xff08;ASIC_Flow&#xff1b;付费项目补充&#xff09; 更新说明项目整体框图神经网络框图File tree 项目简介和学习目的软件环境要求 Area、QOR、Power&Timing报告Area & QORTiming & Power 总结 更新说…

【C++】类与对象(一)

前言 类与对象&#xff08;一&#xff09; 文章目录 一、面向对象和面向过程的对比二、类的引入2.1 C中的结构体2.2 类2.3 类定义方法2.4 修饰限定符2.5 封装2.6 类的实例化2.7 类对象的大小 三、this指针3.1 this 指针的使用 一、面向对象和面向过程的对比 面向过程编程是将程…

GoJS—交互式图表开发的神器(海量案例)

一、GoJS是什么&#xff1a; GoJS是一个用于创建交互式可视化图表和图形的JavaScript库。它提供了丰富的功能和工具&#xff0c;使开发人员能够轻松地构建各种类型的图表&#xff0c;包括流程图、组织结构图、网络拓扑图等。GoJS具有灵活的布局和样式设置&#xff0c;可以通过简…

Python中Numba库装饰器

一、运行速度是Python天生的短板 1.1 编译型语言&#xff1a;C 对于编译型语言&#xff0c;开发完成以后需要将所有的源代码都转换成可执行程序&#xff0c;比如 Windows 下的.exe文件&#xff0c;可执行程序里面包含的就是机器码。只要我们拥有可执行程序&#xff0c;就可以随…

基于STM32的智能手环设计与实现

需要原理图工程&#xff0c;源码&#xff0c;PCB工程的朋友收藏&#xff0c;这篇文章关注我&#xff0c;私我吧&#xff01;&#xff01;&#xff01; 基于STM32的智能手环设计与实现 摘要一、研究背景及意义二、实现功能三、系统方案设计系统方案设计框图3.1 单片机芯片选择3…

[HGAME 2023 week1]easyenc

查壳 IDA打开 字符串打开就发现了明显的标志 int __cdecl main(int argc, const char **argv, const char **envp) {__int64 v3; // rbx__int64 v4; // raxchar v5; // alchar *v6; // rcxint v8[10]; // [rsp20h] [rbp-19h]char v9; // [rsp48h] [rbpFh]__int128 v10[3]; //…