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,一经查实,立即删除!

相关文章

启明智显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实现层、框架层和设备适配层。各层基…

Mouse IFN-α ELISA kit (Quick Test)

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

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

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

RREA论文阅读

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

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

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

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

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

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

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

【LeetCode】二叉树类题目详解

二叉树 二叉树的理论基础 二叉树是结点的度数之和不超过2的树,二叉树总共有五种基本形态 二叉树的种类主要有: 满二叉树完全二叉树 二叉树的存储方式 顺序存储链式存储 二叉树的遍历方式 先序遍历(深度优先搜索)中序遍历&…

蓝桥杯-STL-string

目录 字符串定义 字符串初始化 字符串输入输出 字符串输出 字符串输入 字符串访问 字符串拷贝 字符串拼接 直接相加 append(const char*str,int n) 字符串比较 ​编辑字符串长度length()/size() 字符串查找find(string str) 查找子串substr(int a,int b) 字符串的…

秋招数据库学习2(20240408-20240412共10道)

由于感觉数据库难度可能暂时面试用不到,就先不刷啦 20240408 1.从不订购的客户 SELECT Name AS Customers FROM Customers C LEFT JOIN Orders O ON C.Id O.CustomerId WHERE CustomerId is nullselect customers.name as Customers from Customers wher…

手写ArrrayList

需求 自定义的MyArrayList import java.util.Arrays; import java.util.Objects;public class MyArrayList<E> {private Object[] elementData ; // 存储元素的数组private int size; // 记录 的元素个数private static final int DEFAULT_CAPACITY 10; // 默认容量// …

Eigen笔记2:矩阵拼接

直接贴代码吧&#xff0c;使用的MatrixXd 和<<运算符&#xff1a; int main(int argc, char *argv[]) {Eigen::MatrixXd B(2, 2);B << 1, 2,3, 4;Eigen::MatrixXd C(2, 2);C << 5, 6,7, 8;Eigen::MatrixXd D(2, 2);D << 9, 10,11, 12;Eigen::MatrixXd…

基于React封装Handsontable并兼容antd

背景 其实Handsontable官方也提供了React的版本&#xff0c;但是官方的版本再编辑和渲染的时候并不能够很好的嵌入第三方的组件库。这就导致了&#xff0c;使用了Handsontable就没有办和普通的react项目一样轻松引用其他第三方组件。因此对其react的版本进行了二次的封装&#…

Django中间件路由映射自动加/斜杠问题原因及分析

输入 http://127.0.0.1:8000/main/index/ 输入 http://127.0.0.1:8000/main/index 路由定义情况 urlpatterns [path("index/", views.index) ]可以发现我在输入URL的index路由时&#xff0c;如果没有和Django定义的路由匹配规则一样的话&#xff0c;浏览器自…

Vim:强大的文本编辑器

文章目录 Vim&#xff1a;强大的文本编辑器Vim的模式命令模式常用操作光标移动文本编辑查找和替换 底行命令模式常用操作Vim的多窗口操作批量注释与去注释Vim插件推荐&#xff1a;vimforcpp结论 Vim&#xff1a;强大的文本编辑器 Vim&#xff0c;代表 Vi IMproved&#xff0c;…

如何确保软件通过SmartScreen验证,消除用户下载时的警告提示?

在当前的网络时代&#xff0c;各种软件应用程序深深渗透到人们的日常生活和工作中&#xff0c;许多企业选择自行开发应用程序以推进其业务发展。但在发布应用程序后&#xff0c;软件所有者经常会遇到一个挑战&#xff0c;即用户在下载时可能会遇到微软SmartScreen提示“此应用程…