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.rhkb.cn/news/307081.html

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

相关文章

Android 纵向双选日历

这个日历的布局分两部分&#xff0c;一部分是显示星期几的LinearLayout&#xff0c;另外就是一个RecyclerView&#xff0c;负责纵向滚动了。 工具类&#xff1a; implementation com.blankj:utilcode:1.17.3上activity_calendar代码&#xff1a; <?xml version"1.0&…

【CSS面试题】Flex实现九宫格

考察知识&#xff1a; flex布局 水平垂直居中的实现 初始效果 代码关键&#xff1a;给父盒子添加以下属性 flex-wrap: wrap; /* 允许换行 */justify-content: space-around; /* 主轴对齐方式 */align-content: space-around; /* 多行在侧轴上的对齐方式 */<!DOCTYPE html&…

关于阿里云centos系统下宝塔面板部署django/中pip install mysqlclient失败问题的大总结/阿里云使用oss长期访问凭证

python版本3.12.0 项目的版本依赖 问题1 解决方案 sudo vim /etc/profile export MYSQLCLIENT_CFLAGS"-I/usr/include/mysql" export MYSQLCLIENT_LDFLAGS"-L/usr/lib64/mysql" Esc退出编辑模式 &#xff1a;wq退出并且保存 问题二 说是找不到 mysql.h头…

大数据入门之如何利用Phoenix访问Hbase

在大数据的世界里&#xff0c;HBase和Phoenix可谓是一对黄金搭档。HBase以其高效的列式存储和强大的数据扩展能力&#xff0c;成为大数据存储领域的佼佼者&#xff1b;而Phoenix则以其SQL化的操作方式&#xff0c;简化了对HBase的访问过程。今天&#xff0c;就让我们一起看看如…

LC 515.在每个树行中找最大值

515. 在每个树行中找最大值 给定一棵二叉树的根节点 root &#xff0c;请找出该二叉树中每一层的最大值。 示例1&#xff1a; 输入: root [1,3,2,5,3,null,9] 输出: [1,3,9] 示例2&#xff1a; 输入: root [1,2,3] 输出: [1,3] 提示&#xff1a; 二叉树的节点个数的范围是…

【单片机毕业设计8-基于stm32c8t6的RFID校园门禁系统】

【单片机毕业设计8-基于stm32c8t6的RFID校园门禁系统】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇8基于stm32的RFID校园门禁系统 &#x1f9ff;创作不易&#xff0c;拒绝白嫖可私 一、功能介绍 -----------…

【SVN】clean up报错:Cleanup failed to process the following paths 解决方法

报错来源&#xff1a;代码更新有一个文件既不能接受自己的也不能接受别人的&#xff0c;只能取消&#xff0c;再提交提醒clean up&#xff0c;随后报标题错误。 解决方法&#xff1a;参考https://www.cnblogs.com/pinpin/p/11395438.html 注&#xff1a;如果clean up的时候有…

Python(10):常见的4种设计模式(单例/工厂/策略/观察者)

文章目录 一、单例模式二、工厂模式三、策略模式四、观察者模式 程序中设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案&#xff0c;这些解决方案是众多软件按开发人员经过相当长的一段时间的实验和错误总结出来的。使用设计模式是为了重用代码、让代码更容易…

SSL数字证书

SSL数字证书产品提供商主要来自于国外&#xff0c;尤其是美国&#xff0c;原理和使用操作系统一样&#xff0c;区别在于SSL数字证书目前无法替代性&#xff0c;要想达到兼容性99%的机构目前全球才3-4家&#xff0c;目前国内的主流网站主要使用的是国际证书&#xff0c;除了考虑…

文章分享:《二代测序临床报告解读指引》

&#xff3b;摘要&#xff3d; 二代测序&#xff08;next generation sequencing&#xff0c;NGS&#xff09;已成为中国临床肿瘤医生常用检测工具&#xff0c;而中国超 90%临床医生需要 NGS 报告解读支持。因此&#xff0c;为提升临床医生 NGS 报告解读能力&#xff0c;特编写…

django基于python的法院执法案件管理系统

本课题使用Python语言进行开发。代码层面的操作主要在PyCharm中进行&#xff0c;将系统所使用到的表以及数据存储到MySQL数据库中&#xff0c;方便对数据进行操作本课题基于WEB的开发平台&#xff0c;设计的基本思路是&#xff1a; 框架&#xff1a;django/flask 后端&#xff…

AWE2024酷开科技智能家居,让生活从此更智能!

随着科技的飞速发展&#xff0c;智能家居已经成为了人们生活中不可或缺的一部分。在这个领域里&#xff0c;酷开科技品类逐渐丰富&#xff0c;在AWE2024展会上展现出耀眼光芒&#xff0c;将全品类智能家电新品集结亮相&#xff01;让人们的生活更加便捷、舒适和智能化。 酷开K…

C++的stack和queue类(三):适配所有容器的反向迭代器

目录 前言 list的反向迭代器 list.h文件 ReverseIterator.h文件 test.cpp文件 前言 迭代器按性质分类&#xff1a; 单向&#xff1a;forward_list双向&#xff1a;list随机&#xff1a;vector / deque 迭代器按功能分类&#xff1a; 正向反向const list的反向迭代器…

elementUI 下拉框加提示文案

效果如下&#xff1a; 展示文案在最下面&#xff0c;跟选项有个分割线 <el-select v-model"value" placeholder"请选择" clearable popper-class"addNotice" class"addNoticeS" visible-change"(v) >selectNotice(v,展示…

独一无二:探索单例模式在现代编程中的奥秘与实践

设计模式在软件开发中扮演着至关重要的角色&#xff0c;它们是解决特定问题的经典方法。在众多设计模式中&#xff0c;单例模式因其独特的应用场景和简洁的实现而广受欢迎。本文将从多个角度详细介绍单例模式&#xff0c;帮助你理解它的定义、实现、应用以及潜在的限制。 1. 什…

书生·浦语大模型实战营 | 第3次学习笔记

前言 书生浦语大模型应用实战营 第二期正在开营&#xff0c;欢迎大家来学习。&#xff08;参与链接&#xff1a;https://mp.weixin.qq.com/s/YYSr3re6IduLJCAh-jgZqg 第三堂课的视频链接&#xff1a;https://www.bilibili.com/video/BV1QA4m1F7t4/ 本次笔记是学习完第三堂课…

vueRouter动态路由(实现菜单权限控制)

一、权限控制管理&#xff1a; 对于企业级的项目, 我们可能需要对项目做权限控制管理, 实现不同角色的用户登录项目根据所拥有的权限访问不同的页面内容&#xff0c;此时就需要使用到动态路由来对权限页面做限制。 【使用vue-router实现动态路由&#xff0c;达到实现菜单权限…

FFmpeg: 简易ijkplayer播放器实现--06封装打开和关闭stream

文章目录 流程图stream openstream close 流程图 stream open 初始化SDL以允许⾳频输出&#xff1b;初始化帧Frame队列初始化包Packet队列初始化时钟Clock初始化音量创建解复用读取线程read_thread创建视频刷新线程video_refresh_thread int FFPlayer::stream_open(const cha…

Docker 学习笔记(七):介绍 Dockerfile 相关知识,使用 Dockerfile 构建自己的 centos 镜像

一、前言 记录时间 [2024-4-12] 系列文章简摘&#xff1a; Docker学习笔记&#xff08;二&#xff09;&#xff1a;在Linux中部署Docker&#xff08;Centos7下安装docker、环境配置&#xff0c;以及镜像简单使用&#xff09; Docker 学习笔记&#xff08;三&#xff09;&#x…

【MoS2】应变增强的单层MoS2光电探测器

这篇文章的标题是《Strain-Enhanced Large-Area Monolayer MoS2 Photodetectors》&#xff0c;作者是Borna Radatovic等人&#xff0c;发表在《ACS Applied Materials & Interfaces》期刊的2024年第16卷。文章主要研究了应变增强的大面积单层MoS2光电探测器的性能和应用潜力…