C++ 类和对象 上

目录

前言

什么是面向对象?什么是面向过程?

面向过程

面向对象

 比较

引入

定义

实例化

类的大小

this指针


前言

        今天我们来进入C++类和对象的学习。相信大家一定听说过C语言是面向过程的语言,而C++是面向对象的语言?那么他们有什么却别呢?又怎么体现呢?这就与我们今天要说的类和对象脱不了关系了。

什么是面向对象?什么是面向过程?

面向过程

        面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。

        面向过程(Procedure Oriented)是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程。

        这是两种方法的官方解释,我们首先要明白的是不论是面向过程还是面向对象他们的最终目的都是解决具体的问题,只是角度不同罢了。下面举个具体的例子来看。

        比如现在我们要洗衣服。如果以面向过程的思想,那么它应该按照如下的思路进行

        紧接着我们用代码标识上述的一些列操作,先定义个盆,设置盛水量等自定义变量,然后写个放水的函数,再放洗衣粉,手搓……最后晾衣服。可以看出面向过程就是按照事物的发展逐步的解决问题,符合我们的直觉,当我们知道具体的过程时,便可以一步步的实现代码,将洗衣服的大事不断化小,分解,最终再汇总就解决了问题。

        当然面向过程的实现代码的难度不会太高,只要我们知道了一件事的过程便可以逐步的解决。化大为小,通过不断地解决子问题最总解决问题。


面向对象

        不难发现,在C语言中数据和函数是分离的。我们不能在自定义的类型如struct中实现函数,要想使用函数,必须给函数传递数据的参数,然后进行处理。但在C++中数据和函数是紧密结合的,像这样的自定义类型不只包含数据,还有函数的就可以称为类。

        还是上面洗衣服的例子。假如我们以面向对象的思想看待这个问题,我们该如何做呢?

        首先我们要抽象出来对象,就可以理解为我们要操作的数据,对象就有人,盆,洗衣机,衣服,而接水,手搓,拧干就可以看为数据的处理,即类的函数。

        

        我们接着就调用人类中的拿衣服函数,然后盆类装衣服函数,假如洗衣粉函数,然后再调用人类中的洗衣函数,最后调用人类中的晒衣服函数。

        可以看出,所谓的面向对象就是从一件事情中抽象出对象,然后在对象间处理事情。

        面向对象看起来十分的简单,只需要不断地调用函数,但这些函数却是要我们自己一一实现的,与面向过程最大的不同是将函数与数据封装在一起。可以说是从另外一个思想角度上解决了问题。但类还有许多巨大的优势,例如简化代码,在类中实现函数不需要传太多的参数,安全性提高,命名冲突大大减少,代码复用性好等,我们在后面会一一介绍。

 比较

        有个恰当的比喻是,面向过程是编年体,以时间为线索记录历史,面向对象是纪传体,以人物为线索记录历史,二者殊途而同归。同样面向过程就是按照我们理解的事情发展而不断地写函数处理,而面向对象是先在类中实现类的各种函数,最后再使用。二者最终都可以解决问题。

        从上面看来说,面向对象和面向过程复杂度没有太大区别,但面向对象又发展出了三大特性,封装,继承,多态。这个我们会在后面说,这几种重要的性质大大简化了面向对象开发的复杂度。

        接下来我们正式的了解类的概念和用法。

引入

        在正式的说类之前,我们先看一个我们熟悉的C语言结构体知识。

struct Date
{int year;int month;int day;
};void DateInit(struct Date* p,int year,int month,int day)
{p->day = day;p->month = month;p->year = year;
}void DatePrint(struct Date* p)
{printf("%d-%d-%d\n",p->year,p->month,p->day);
}int main()
{struct Date t;DateInit(&t, 2024, 4, 11);DatePrint(&t);return 0;
}

        我们定义了一个日期结构体,然后打印出日期。函数名为了不与其他的函数混淆,同一加上了Date, DatePrint,DateInit,当然就目前的小段程序而言不需要区分,但加了区分是一个好习惯。

        可能会有读者十分疑惑?不是要讲类么,怎么讲了结构体。我们要明白没有人可以什么都从无到有的创造,我们要学会站在巨人的肩膀上。类可以看为C语言结构体的PLUS版。

定义

        类的定义十分简单如下

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

        其内部的成员又可以被操作符public: private: protected:修饰从而产生不同的用法。是不是与结构体十分相似,看起来不过加个三个修饰符并且支持内置函数。但这几个用法较为复杂,我们后序再做介绍。

        由此我们便可以将上面C语言的代码用C++写出来。

struct Date
{int _year;int _month;int _day;void Init( int year, int month, int day){_day = day;_month = month;_year = year;}void Print(){printf("%d-%d-%d\n", _year, _month, _day);}};int main()
{Date t;t.Init(2024, 4, 11);t.Print();return 0;
}

        首先我们要明白,类里面的变量,函数存在类的命名空间内,俗称类域。这样我们的函数名就不需要加上Date标识符了,即使其他的类也有Init函数,但他们处于不同的命名空间中,不会发生命名冲突。其次我们也不需要传递结构体的指针了,或者说不需要我们人为的传递指针,在类的里面函数可以直接调用内置类型。是不是相对于C语言来说简化了许多代码了!!

        上述的struct Date也可以称之为类,但大家看见更多的可能是class Date,他们都可以称之为类。但C++为了衔接C语言,将struct Date默认数据类型用public:修饰,class Date默认类型用private:修饰。他们的区别如下。

        当然访问限定符的区别不知有上面的,更多的在类的继承模块,在这里就不多讲了。其次访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。 如果后面没有访问限定符,作用域就到}即类结束。

        除了默认访问权限的不同,struct Date与class Date基本没有区别,但我们定义类一般用class,与以前的结构体做区分。

        我们保存的日期数据肯定是不希望其他人随便更改的,于是便可以使用访问限定符,只流出一定的接口函数给别人使用,对于最基础的数据禁止直接修改访问。如下代码。

class Date
{
public:void Init( int year, int month, int day){_day = day;_month = month;_year = year;}void Print(){printf("%d-%d-%d\n", _year, _month, _day);}private:int _year;int _month;int _day;
};

        假如我们在类的外面修改 _year,便会报出如下错误。

实例化

       此时我们再次回到刚才类的代码上。我们思考一个问题?这段代码是声明还是定义?

class Date
{
public:void Init( int year, int month, int day){_day = day;_month = month;_year = year;}void Print(){printf("%d-%d-%d\n", _year, _month, _day);}private:int _year;int _month;int _day;
};

        我们要区别声明和定义首先要了解他们的区别,简单来说定义就是开辟一段空间然后可以存储对应的数据,而声明不开辟空间,仅仅是告诉编译器有这个变量或者函数。显然我们上述的代码是一段声明,并没有开辟一段空间。而下面一段代码则不同。

Date t;

        它就是定义了一个Date变量,开辟了空间。我们可以把类称之为一种自定义类型的变量类型,所谓实例化就是用这个变量类型开辟空间,定义变量。

        我们可以把类看为房子的设计图纸,而对象就是根据类实现的房子。如下图

类的大小

        说完实例化,我们紧接着来看类的大小,我们前面提到过类与C语言的结构体是血脉相连的,结构体计算内存采用的内存对齐在类中也有。

        下面是结构体内存对齐规则,在类中变量也遵循如下的规则。

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

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

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

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

        但类比C语言多了个函数,那么函数如何计算内存呢?

        我们先看如下使用场景。

int main()
{Date t;t.Init(2024, 4, 11);t.Print();Date t2;t2.Init(2024, 4, 11);t2.Print();Date t3;t3.Init(2024, 4, 11);t3.Print();Date t4;t4.Init(2024, 4, 11);t4.Print();return 0;
}

        这个代码十分简单,创建四个对象,并且初始化,打印。对于成员函数而言,他们在接受参数后,会根据参数进行处理。那么我们四次打印,初始化的代码逻辑是不是相同的,只不过实参不同罢了。如果我们给每个对象都保存一份成员函数,是不是大大的浪费了使用空间,于是C++就规定,类的成员函数不计算内存,类的成员函数代码保存在系统的代码区。

        于是我们可以用关键字sizeof求出类的大小,除非不给用sizeof,否则不要自己算!这里为了让大家理解,会带着大家算一遍。

        为什么这样呢?看如下示意图。

        有的读者可能觉得这不就是三个int相加么?但这只是一种巧合,下面我们稍微修改代码在计算一次。

class Date
{
public:void Init( int year, int month, int day){_day = day;_month = month;_year = year;}void Print(){printf("%d-%d-%d\n", _year, _month, _day);}private:int _year;char t;int _month;int _day;
};

        大家可以先自行计算,然后看下面的分析。

        我们也可以用程序检测下。可以看出此时类的大小也为16.

        关于大小我们最后再看一个特殊的情况空类。如下代码

class pr
{};

        那么他的大小是多少呢?为0还是什么?

        可以看出他的大小为1,这也是C++的规定之一,空类的大小为1.也就是说类的大小至少为1.

        C++做了这个规定,可能也是为了如下代码考虑,用空类定义了一个对象,属于定义还是声明。如果空类的大小为0,那么就不符合定义的基本条件开辟内存,划为声明有有些不和常量,所以最后规定空类的大小为1.

int main()
{pr t;printf("%d", sizeof(pr));return 0;
}

this指针

        接下来我们来认识个C++关键字this,它有什么意义呢?

        我们回头看上面的一段程序

int main()
{Date t;t.Init(2024, 4, 11);t.Print();Date t2;t2.Init(2024, 4, 11);t2.Print();Date t3;t3.Init(2024, 4, 11);t3.Print();Date t4;t4.Init(2024, 4, 11);t4.Print();return 0;
}

        对于每个t.Init(2024, 4, 11);操作我们只提供了对应要初始化的值,编译器如何才能找到对于的变量对其进行初始化,而不会找错对象。我们回顾C语言对结构体初始化的程序,如下代码。我们为什么可以精准的找到对应变量并对齐进行初始化。我们传递了个结构体指针保证了我们不会出错。

void DateInit(struct Date* p,int year,int month,int day)
{p->day = day;p->month = month;p->year = year;
}

        回到C++,我们写出t2.Init(2024, 4, 11);的函数,也能初始化,其实是编译器帮我们默认传递了一个类的指针!!在类中用this表示。并不是C++语言多神秘,只是编译器帮我们做了许多底层的工作,帮助我们更好的使用语言。我们也可以简单的看下汇编代码。

        编译器在背后做出了巨大的奉献!!方便我们使用。

        今天的文章就到此结束了,大家喜欢的点点关注!

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

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

相关文章

SQLMap简单注入教程

SQLmap是一个自动化的SQL注入工具,支持多种数据库和注入技术,能够检测和利用Web应用程序中的SQL注入漏洞。下面是一个关于SQLmap注入的教程,帮助你了解如何使用SQLmap进行SQL注入攻击。 一、SQLmap的基本原理 SQLmap通过分析目标网站的结构和…

启明智显M系列--工业级HMI芯片选型表

本章主要介绍启明智显M系列HMI主控芯片: 纯国产自主, RISC-V 内核,配备强大的 2D 图形加速处理器、PNG/JPEG 解码引擎、H.264解码;工业宽温,提供全开源SDK;1秒快速开机启动的特性,极大地提高了…

llama-factory SFT系列教程 (三),chatglm3-6B 命名实体识别实战

背景 llama-factory SFT系列教程 (一),大模型 API 部署与使用llama-factory SFT系列教程 (二),大模型在自定义数据集 lora 训练与部署本文为llama-factory SFT系列教程 第三篇 简介 利用 llama-factory 框架,基于 chatglm3-6B 模型 做命名…

【MySQL】事务篇

SueWakeup 个人主页:SueWakeup 系列专栏:学习技术栈 个性签名:保留赤子之心也许是种幸运吧 目录 本系列专栏 1. 什么是事务 2. 事务的特征 原子性(Atomicity) 一致性(Consistency) 隔离性&…

# Contrastive Learning(对比学习)--CLIP笔记(一)

Contrastive Learning(对比学习)–CLIP笔记(一) 参考:CLIP 论文逐段精读【论文精读】_哔哩哔哩_bilibili CLIP简介 CLIP是一种多模态预训练模型,由OpenAI在2021年提出,论文标题:L…

Harmony鸿蒙南向外设驱动开发-Camera

功能简介 OpenHarmony相机驱动框架模型对上实现相机HDI(Hardware Device Interface)接口,对下实现相机Pipeline模型,管理相机各个硬件设备。 该驱动框架模型内部分为三层,依次为HDI实现层、框架层和设备适配层。各层基…

搜索(未完结版)

前言 图的基础与遍历 图的存储方式 邻接表 List<int []>list[N]; list[x]存储x的所有出点的信息。 list[i][j]{first,second}其中first表示从i出发的某个出点的编号&#xff0c;second表示边权。 list[1]{{2,0},{3,0}} 1这个点有2和3连个出边 邻接矩阵 d…

Mouse IFN-α ELISA kit (Quick Test)

干扰素α&#xff08;IFN-α&#xff09;是一类由免疫细胞分泌的内源性调节因子&#xff0c;也被称为白细胞干扰素&#xff0c;主要参与响应病毒感染的先天性免疫。 基于结构特征、受体、细胞来源和生物活性的不同&#xff0c;干扰素可被分为Ⅰ、Ⅱ、Ⅲ三种类型&#xff0c;其中…

一起学习python——基础篇(17)

今天我说一下python中有关文件的操作。 1、检测一个目录里面有无这个文件夹、有无txt文件&#xff0c;代码如下&#xff1a; import os #文件的路径 testPath"D:/pythonFile" testPath2"D:/pythonFile/test.txt" #使用exists()方法检查是否存在文件…

springboot项目如何配置跨域?

在Spring Boot项目中配置跨域&#xff08;CORS&#xff0c;Cross-Origin Resource Sharing&#xff09;主要是为了允许来自不同源&#xff08;不同的协议、域名或端口&#xff09;的前端应用能够访问后端API。Spring Boot提供了多种方式来配置跨域支持。 1. 使用CrossOrigin注…

一篇详解CSS样式

华子目录 CSS常见样式CSS基本语法 文本样式color颜色名称十六进制颜色代码rgb&#xff0c;rgbahsl、hsla预定义颜色值transparent颜色继承 font-stylefont-weightline-heighttext-shadowbox-shadowtext-transformwhite-spacedirection 列表样式list-style-typelist-style-image…

C#:成绩等级转换

任务描述 本关任务&#xff1a;给出一百分制成绩&#xff0c;要求输出成绩等级‘A’、‘B’、‘C’、‘D’、‘E’。 90分以上为A 80-89分为B 70-79分为C 60-69分为D 60分以下为E&#xff0c;如果输入数据不在0~100范围内&#xff0c;请输出一行&#xff1a;“Score is error!”…

RREA论文阅读

Relational Reflection Entity Alignment 关系反射实体对齐 ABSTRACT 实体对齐旨在识别来自不同知识图谱(KG)的等效实体对&#xff0c;这对于集成多源知识图谱至关重要。最近&#xff0c;随着 GNN 在实体对齐中的引入&#xff0c;近期模型的架构变得越来越复杂。我们甚至在这…

为什么tcp需要四次挥手?

首先;我们需要先简单解释下tcp四次挥手都做了什么: tcp终止一个连接&#xff0c;需要经过四次挥手 第一次挥手&#xff1a;客户端发送一个 FIN 报文&#xff0c;报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态&#xff0c;表示停止发送数据&#xff0c;等待服务端的…

Power BI报告在PPT中实时刷新的实现技巧分享

前面我们刚介绍了如何在PPT中展示Power BI报告&#xff1f; 很巧的是&#xff0c;在刚刚的Power BI 2024年4月更新的诸多新特性中&#xff0c;PPT中使用的Power BI插件又有新特性的更新&#xff0c;数据自动刷新功能(新特性仅限国际版使用)&#xff0c;这个新特性支持最低15秒…

已解决javax.xml.bind.JAXBException: JAXB异常的正确解决方法,亲测有效!!!

已解决javax.xml.bind.JAXBException: JAXB异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 报错原因 解决思路 解决方法 审核类定义 检查注解 验证上下文路径 测试序列化与反序列化 适应环境变化 总结 博主v&#xff1…

【3】c++多线程技术之线程同步与互斥

1、线程安全问题与数据竞争 线程安全问题与数据竞争是多线程编程中的重要概念。在C++中,线程安全问题主要涉及到多个线程对共享数据的访问,如果多个线程同时访问同一块内存区域,并且至少有一个线程对该区域进行写入操作,那么就可能发生数据竞争(Data Race)。数据竞争可能…

软件定义车队面临网络安全的曲折之路

当以色列 REE Automotive 设计其 P7 电动汽车底盘时&#xff0c;它是从软件开始工作的&#xff1a;扁平的车辆底盘完全可配置&#xff0c;每个轮胎附近有四个独立的模块&#xff0c;用于转向、制动、悬架和动力传动系统&#xff0c;每个模块均由电子驱动控制单元&#xff08;EC…

网络协议——OSPF(开放式最短路径优先)详解

1.什么是OSPF 开放式最短路径优先OSPF 是一种动态的高度可靠和高度可扩展的路由协议&#xff0c;用于构建大型网络中的动态路由系统 2. OSPF的协议号为&#xff1a;89 3. OSPF的特点: OSPF是链路状态协议使用了区域概念&#xff1a;减少路由选择协议对路由器CPU&#xff0c;…

2022年全国青少年信息素养大赛python初赛真题

这份文档包含了Python初赛的真题,涉及到Python编程的核心知识点,如变量、函数、条件语句、循环语句、导入库等。具体来说,文档中涉及到以下考点: - 变量:包括变量的定义、变量的初始化、变量的赋值、变量的递增、变量的递减等。 - 函数:包括函数的定义、函数的调用、函…