当前位置: 首页 > news >正文

【逐步剖C++】-第一章-C++类和对象(上)

前言:本文主要介绍有关C++入门需掌握的基础知识,包括但不限于以下几个方面,这里是文章导图:
在这里插入图片描述

本文较长,内容较多,大家可以根据需求跳转到自己感兴趣的部分,希望能对读者有一些帮助
那么本文也主要以导图为思路进行分享,话不多说,让我们开始吧。

一、关于类的理解与意义

1、理解

什么是类呢?可以直接根据其表面来理解。这个“类”我们常说的给事物分类的“类”,比如,动物类,交通工具类等等。通过给不同的事物进行分类,能让我们更有条理性、更系统地认知这个世界。同样的道理,类的设计可以让我们的代码编写更具逻辑性、可维护性等等。以上就是对类的简单理解。

2、意义

那么类的设计有什么意义呢?基本的意义上述也提到了,能增强代码的可维护性等,它能将具有协同功能代码封装成一个整体,从而更好地进行管理;更多对其意义的感知还是需要通过不断的学习,和代码实践来逐步加强。

关于类和对象的更形象理解方式大家感兴趣地可以去搜搜文章和书籍,本文主要还是以学习笔记的方式来展现知识内容,这里就不再赘述。

二、类的定义方式

1、关于兼容C后的结构体

由于C++兼容C,所以在C++中结构体被升级成了类。在C中的结构体只能定义成员变量,升级成类后也可以定义成员函数。但二者仍有一些区别,下文会继续进行说明。

2、定义方式

类的定义方式如下:

class typename
{};

其中class为定义类的关键字;typename为用于定义该类的类名;花括号中为类的具体内容;最后别忘了分号。

在实际工程中定义类时,我们可以根据需求将类声明(主要是其中成员函数的声明)放在头文件中,在.cpp文件中再对类中的成员函数进行定义。

三、类的访问限定符及封装的理解

类访问限定符是C++实现封装的主要方式。通过访问限定符,可以选择性地将类中的成员展现给外界用户。和平常被我们使用的电子产品一样,都是将简单易用的功能展现给我们,而将复杂的实现细节封装起来

1.类的访问限定符

(1)类的访问限定符一共有三种,分别是:publicprotectedprivate
对以上三种访问限定符的说明如下:

  • 被pubilc修饰的成员能在类外直接访问
  • 被protected和private修饰的成员不能在类外直接访问,(PS:关于protected和private的区别在继承章节会提到,平常使用可认为二者类似
  • 访问限定符的作用范围是:从当前访问限定符开始到下一个访问限定符出现;若下一个访问限定符一直未出现,则右花括号为止。
  • class关键字定义的类默认的访问权限为private;struct关键字定义的类的默认范围权限为public(兼容C)

(2)类访问限定符在程序生命周期中作用的阶段:编译阶段。即访问限定符只在编译阶段有用,当数据映射到内存后,没有任何访问限定符上的区别。

2、对封装的理解

封装是面向对象的三大特性之一(封装、继承、多态)。对封装的理解其实很简单,前文也有谈到,其实就是将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,对外仅公开使用工具(接口)来和对象进行交互。本质上属于一种管理,让用户更方便的使用类,也让类的设计更加规范化。

四、类的作用域与实例化

1、类的作用域

类的作用域也属于“域”的一种,至此我们所认识的“域”,一共就有如下三种:

  • 局部作用域
  • 全局作用域
  • 命名空间域
  • 类作用域

在笔者的另一篇文章【逐步剖C++】-第一章-C++入门知识的命名空间部分中,提到了用域访问符::访问命名空间,这里我们也有该符号的使用需求,请看:
在类外定义成员函数时,需使用域访问符指明成员函数属于哪个类域,请看下面代码例:

class test
{
public:void testFunc();
}void test::testFunc()
{//...
}

2、类的实例化

类的实例化,本质就是通过类创建一个对象,实例化出来的对象占实际的物理空间,存储类的成员变量。由此可见,类在没有实例化之前,系统并没有为其成员变量并开实际的空间,在这个阶段成员变量仅是声明;当进行类的实例化时,成员变量才得到整体定义。

这里有一个形象的理解方式:
类的实例化过程就像拿着建筑设计图造出房子的过程。类就好比设计图,仅对房子中的内容、布局等进行规划与设计,并没有实体的建筑存在。所以,仅有一个类的定义本质是不占空间的,只有实例化出对象后,才占物理空间而实际存储数据;同理也不能直接在类外对类中声明的成员变量进行赋值,就好比设计图中不能直接住人

五、类对象的大小计算

这里通过三个类的例子进行对类对象的大小计算的说明:

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

上面三个类实例化出的对象的大小分别为4字节、1字节、1字节。
解释:
在类中,对于成员变量成员函数的大小计算不同:

  • 对于成员变量,相同类实例化出的每个对象的成员变量是不一样的,就好比同一张设计图造出来的房子都有卧室,但这两个卧室一定是不同的;计算它们的大小时,和结构体一样,采用内存对齐的方法进行计算即可。关于内存对齐,可以看看笔者这篇文章:【逐步剖C】-第十章-自定义类型之结构体、枚举、联合
  • 对于成员函数,相同类实例化出的每个对象其实是一样的,成员函数就像是篮球场、健身房等场所,不用每家都建而建成公共的,这样就避免了由于重复而引起的空间浪费,那么类中的成员函数存储方式类似,其会以成员函数表的形式放在一个公共的代码段中,当类的对象需要调用成员函数时,就到这个公共代码段中找对应的函数地址来完成调用,其实际不在类中(不占空间)。

验证

class A
{
public:void Test(){cout << "void Test()" << endl;cout << _a << endl;}
private:int _a = 0;		//成员变量缺省值,后续章节会说明
};
int main()
{A a1;A a2;a1.Test();a2.Test();
}

运行后转到反汇编:
在这里插入图片描述
可以看到,同一个类的两个不同对象所调用的成员函数的地址相同PS:图中红框就是代码中的Test函数,蓝框是A类的默认构造函数,后续章节会进行说明)。

那么在最开始的代码例中,类A1的大小即为其成员变量的大小;类A2和类A3的大小类似,编译器会给他们一个字节来唯一标识这个类的对象。

六、this指针

1、this指针的本质

场景引入:在上面的例子中,我们通过类A实例化了两个对象,并且这两个对象都调用了成员函数Test(),那么编译器是如何知道是哪个对象调用的呢?这就是this指针解决的问题了。

C++编译器给每个非静态的成员函数增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),指针中的内容即为对象本身的地址,在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
即例子中两条调用语句其实可理解为:

a1.Test(&a1);
a2.Test(&a2);

需要注意的是,如上仅作为一种理解方式,实际不能这么写,因为编译器规定this指针不能在实参和形参显示传递,仅可以在成员函数内部显示使用
如:

class A
{
public:void Test(){cout << "void Test()" << endl;cout << _a << endl;		//编译器自动处理this指针//也可显示使用写为:cout << this->_a << endl;}
private:int _a = 0;		//成员变量缺省值,后续章节会说明
};

2、this指针的特性

  • this指针的类型其实为const 类的类型*,如上A类的对象的this指针类型就为A* const,即不能改变指针所指向的对象,而可以改变对象中的具体内容(成员变量等);
  • 只能在成员函数中显示调用;
  • this指针本质上是成员函数形参,当对象调用成员函数时,编译器一般通过ecx寄存器自动将对象地址作为实参传递给该形参。故在类的对象中不存储this指针

3、关于this指针的一些问题

了解了this指针的特性后,下面有一些常被提起的关于this指针的问题,请看:

  • this指针可以为空吗
    可以通过下面这一段代码来认识并解决这个问题:
class A
{public:void Print(){cout << "Print()" << endl;}void PrintA(){cout << _a << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->Print();p->PrintA();return 0;
}

p是一个A类对象的指针,将其赋值为空指针后用以模仿this指针来调用A类中的成员函数。运行结果如下:
在这里插入图片描述
可以看到,第一个函数Print()正常调用,在调用第二个函数时系统崩溃。原因很明显:p是一个空指针,在调用第一个成员函数时,本质上并没有访问该指针所指向位置的内存(对象的具体内容);而在调用第二个成员函数时,程序想访问并输出类的成员变量_a,那么此时的行为就相当于解引用一个空指针而去访问其指向的内容,也就是我们常说的野指针问题,故造成了程序的崩溃。
综上,this指针一般情况下不会为空。

  • this指针存储在哪里
    第二个问题其实在介绍this指针的特性时已给出了答案,this指针本质上是成员函数的形参,那么既然是形参,也就是局部变量,那就一定存储在栈区当中。

本章完。

看完觉得有觉得帮助的话不妨点赞收藏鼓励一下,有疑问或有误地方的地方还请过路的朋友们留个评论,多多指点,谢谢朋友们!🌹🌹🌹

相关文章:

【逐步剖C++】-第一章-C++类和对象(上)

前言&#xff1a;本文主要介绍有关C入门需掌握的基础知识&#xff0c;包括但不限于以下几个方面&#xff0c;这里是文章导图&#xff1a; 本文较长&#xff0c;内容较多&#xff0c;大家可以根据需求跳转到自己感兴趣的部分&#xff0c;希望能对读者有一些帮助 那么本文也主要…...

索尼 toio™ 应用创意开发征文|探索创新的玩乐世界——索尼 toio™

导语&#xff1a; 在技术的不断进步和发展中&#xff0c;玩具也逐渐融入了智能化的潮流。索尼 toio™作为一款前沿的智能玩具&#xff0c;给孩子和成人带来了全新的游戏体验。本文将介绍索尼 toio™的特点、功能和应用场景&#xff0c;让读者了解这个令人兴奋的创新产品。 1. 了…...

企业架构LNMP学习笔记23

1、隐藏版本号&#xff1a; Nginx对外提供服务&#xff0c;为了避免被针对某个版本的漏洞进行攻击。经常做法是隐藏掉软件的版本信息&#xff0c;提供一定的安全性。 server_tokens off; https和CA&#xff1a; 1&#xff09;基于SSL CA证书的公私钥的安全性。 CA是需要生成…...

第六章 图 五、图的深度优先遍历(DFS算法)

目录 一、定义 深度优先遍历通常用于解决以下问题&#xff1a; 深度优先遍历算法具有以下优点&#xff1a; 深度优先遍历算法的一个缺点是&#xff1a; 二、代码 空间复杂度&#xff1a; 时间复杂度&#xff1a; 邻接矩阵存储&#xff1a; 邻接表存储&#xff1a; 三、…...

React 中的 useLayoutEffect 钩子函数

useLayoutEffect钩子函数的作用跟useEffect钩子函数的作用一样&#xff0c;它们的不同主要是在于&#xff1a; 1、useEffect钩子函数是异步的&#xff0c;因为此函数在执行的时候是先计算出所有的 Dom 节点的改变后再将对应的 Dom 节点渲染到屏幕上&#xff0c;然而在 useEffe…...

upload-labs1-21关文件上传通关手册

upload-labs文件上传漏洞靶场 目录 upload-labs文件上传漏洞靶场第一关pass-01&#xff1a;第二关Pass-02第三关pass-03&#xff1a;第四关pass-04&#xff1a;第五关pass-05&#xff1a;第六关pass-06&#xff1a;第七关Pass-07第八关Pass-08第九关Pass-09第十关Pass-10第十一…...

MATLAB遗传算法求解生鲜货损制冷时间窗碳排放多成本车辆路径规划问题

MATLAB遗传算法求解生鲜货损制冷时间窗碳排放多成本车辆路径规划问题实例 1、问题描述 已知配送中心和需求门店的地理位置,并且已经获得各个门店的需求量。关于送货时间的要求,门店都有规定的时间窗,对于超过规定时间窗外的配送时间会产生相应的惩罚成本。为保持生鲜农产品的…...

界面控件DevExpress .NET应用安全 Web API v23.1亮点:支持Swagger模式

DevExpress拥有.NET开发需要的所有平台控件&#xff0c;包含600多个UI控件、报表平台、DevExpress Dashboard eXpressApp 框架、适用于 Visual Studio的CodeRush等一系列辅助工具。 DevExpress 今年第一个重要版本v23.1日前已正式发布了&#xff0c;该版本拥有众多新产品和数十…...

SpringMVC之CRUD------增删改查

目录 前言 配置文件 pom.xml文件 web.xml文件 spring-context.xml spring-mvc.xml spring-MyBatis.xml jdbc.properties数据库配置文件 generatorConfig.xml log4j2日志文件 后台 PageBaen.java PageTag.java 切面类 biz层 定义一个接口 再写一个实现类 …...

微信小程序开发教学系列(4)- 抖音小程序组件开发

章节四&#xff1a;抖音小程序组件开发 在本章中&#xff0c;我们将深入探讨抖音小程序的组件开发。组件是抖音小程序中的基本构建块&#xff0c;它们负责展示数据和与用户交互。了解组件的开发方法和使用技巧是进行抖音小程序开发的重要一步。 4.1 抖音小程序的基本组件 抖…...

RabbitMQ反序列化失败:Failed to convert message

&#x1f388; 1 参考文档 RabbitMQ消费消息坑&#xff1a;failed to convert serialized Message content | jiuchengi-cnblogs &#x1f50d;2 问题描述 org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Failed to convert messageat org.sprin…...

CTFSHOW 年CTF

1.除夕 php的弱类型&#xff0c;用小数点绕过 这里后面直接加字母不行 2.初三 error_reporting(0); extract($_GET); include "flag.php"; highlight_file(__FILE__); 这里通过extract将get的参数导入为了变量 $_function($__,$___){return $__$___?$___:$__; }; …...

肖sir__设计测试用例方法之状态迁移法05_(黑盒测试)

设计测试用例方法之状态迁移法 一、状态迁移图 定义&#xff1a;通过描绘系统的状态及引起系统状态转换的事件&#xff0c;来表示系统的行为 案例&#xff1a; &#xff08;1&#xff09; 订机票案例1&#xff1a; l向航空公司打电话预定机票—>此时机票信息处于“完成”状…...

无涯教程-JavaScript - IMPRODUCT函数

描述 IMPRODUCT函数以x yi或x yj文本格式返回1到255个复数的乘积。两个复数的乘积为- $$(A BI)(C DI)(AC-BD)(A B)1 $$ 语法 IMPRODUCT (inumber1, [inumber2] ...)争论 Argument描述Required/OptionalInumber11 to 255 complex numbers to multiply.Required[inumbe…...

yapi以及gitlab的容器化部署

yapi部署&#xff1a; https://blog.csdn.net/Chimengmeng/article/details/132074922 gitlab部署 使用docker-compose.yml version: 3 services: web: image: twang2218/gitlab-ce-zh:10.5 restart: always hostname: 192.168.xx.xx environm…...

TCP、UDP 协议的区别,各自的应用场景

分析&回答 TCP 传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前&#xff0c;必须先在双方之间建立一个TCP连接&#xff0c;之后才能传输数据。TCP提供超时重发&#xff0c;丢弃重复数据&#xff0c;检验数据&#xff0c;流量控制等功能&…...

C高级 DAY3

一、shell中的变量 shell本身是擅长运行指令&#xff0c;是一种弱数据类型语言 它与c语言中定义变量有所不同 C中&#xff1a; 存储类型 数据类型 变量名;shell中&#xff1a; 变量变量的值 ----->如果变量的值中间没有空格直接使用 变量变量的值 ----->变量…...

Linux CentOS7命令及命令行

Linux CentOS7中命令及命令行是非常重要的概念。对大多数初学者来说是既熟悉又了解甚少。本文初步讨论这方面的内容&#xff0c;与同行者交流。 一、命令 命令又称为指令&#xff0c;&#xff08;英语命令 command&#xff0c;可用简写cmd表示&#xff09;&#xff0c;在终端…...

【C++入门到精通】C++入门 ——搜索二叉树(二叉树进阶)

阅读导航 前言一、搜索二叉树简介1. 概念2. 基本操作⭕搜索操作&#x1f36a;搜索操作基本代码&#xff08;非递归&#xff09; ⭕插入操作&#x1f36a;插入操作基本代码&#xff08;非递归&#xff09; ⭕删除操作&#x1f36a;删除操作基本代码&#xff08;非递归&#xff0…...

学成在线-网站搭建

文章目录 代码素材来自b站pink老师 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>学成在线首…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

【堆垛策略】设计方法

堆垛策略的设计是积木堆叠系统的核心&#xff0c;直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法&#xff0c;涵盖基础规则、优化算法和容错机制&#xff1a; 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则&#xff1a; 大尺寸/重量积木在下&#xf…...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...

全面解析数据库:从基础概念到前沿应用​

在数字化时代&#xff0c;数据已成为企业和社会发展的核心资产&#xff0c;而数据库作为存储、管理和处理数据的关键工具&#xff0c;在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理&#xff0c;到社交网络的用户数据存储&#xff0c;再到金融行业的交易记录处理&a…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟

2025年4月29日&#xff0c;在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上&#xff0c;可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞&#xff0c;强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

Monorepo架构: Nx Cloud 扩展能力与缓存加速

借助 Nx Cloud 实现项目协同与加速构建 1 &#xff09; 缓存工作原理分析 在了解了本地缓存和远程缓存之后&#xff0c;我们来探究缓存是如何工作的。以计算文件的哈希串为例&#xff0c;若后续运行任务时文件哈希串未变&#xff0c;系统会直接使用对应的输出和制品文件。 2 …...

多元隐函数 偏导公式

我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式&#xff0c;给定一个隐函数关系&#xff1a; F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 &#x1f9e0; 目标&#xff1a; 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z​、 …...