【C++】类和面向对象很懵?其实很简单

 有不少朋友会遇到这种情况,在学完C++入门的一些知识后,就开始接触类和面向对象的概念,大家去看书、文章的时候都会先抛出一大堆的概念,导致我们听得很懵。那么这篇文章将言简意赅,理解类和面向对象其实很简单!

1. 面向对象与面向过程

其实很多学习编程的人,对于面向过程编程和面向对象编程这两个概念总是搞不清,具体的专业的定义在这里也不去说了,根据上面的叙述,我们可以这样去通俗的解释面向对象。

举个例子:我去洗澡,如果按照面向过程的角度考虑,那么我先进入浴室,然后打开水龙,然后洗漱。然后把身体擦干,也就是说面向过程关注的是解决问题的步骤;如果用面向对象考虑,只需记住一句话,万物皆对象,你是对象,水龙头也是对象,所以我先传递力的参数给浴室门,然后门就开了,然后我在传递消息给水龙头,水龙头得到消息,放水,最后传递消息给毛巾,毛巾利用它吸水的特性,调用吸水方法擦干身体,也就是说面向对象关注的是对象,将一个问题拆分为不同对象,依靠参数完成对象之间的交互 

为什么要进行面向对象编程?这也是一个很值得思考的问题。举个例子,活字印刷术发明之前使用的是雕版印刷,这种方式弊端太大,如果需要改稿,那么雕版就必须重新雕刻,而活字印刷术则解决了这样的问题。需要改动,有可能只需改动几处。面向过程正如雕版印刷一样,也正如做数学题一样,中间某个环节—旦出现需求变更,那么整个工程几乎需要大改,要耗费大量时间精力。面向对像正如活字印刷术一样,如果需求变化了。可能只是修改其中一部分,也就是一个对象,而且最关键的一点是这些对象可以复用,进行活字印刷术一样。不是说这个对象在这个工程中发挥完之后,它就没有价值了,它还可能被其它工程所用。

2. 类的引入

学习C语言时,我们知道,结构体的作用是把一些具有不同类型的变量组合一起。

struct Student
{char _name[20];char _gender[3];int _age;
};

而在C++中,其结构体内不止可以定义变量,而且还可以定义函数。

struct Student
{char _name[20];char _gender[3];int _age;void SetStudentInfo(const char *name,const char *gender,int age){strcpy(_name,name);strcpy(_gender,gender);_age=age;}
};int main()
{Student s;s.SetStudentInfo("Bob","男",18);return 0;
}

这样定义后,结构体就可以被称为,只不过在C++中,我们更喜欢用class代替struct 。

其实我们在定义的时候,和定义结构体差不多,只不过要记住名称换了,而且类里面还可以定义函数

3. 类的定义

3.1 C++类的定义

根据以上叙述,所以在C++中,是这样定义的

class className
{//成员函数//成员变量};//注意分号

所以简单来讲,类就是属性和方法的集合,属性就是类中的数据,方法就是调用这些数据进行操作的函数。 

3.2 类的两种定义方式 

3.2.1 声明和定义全部都放在类体当中

要注意,成员函数如果在类中定义,编译器会将其当做内联函数处理。

class Person //人就是一个类
{public://成员函数void  showInfo()//显示这个人的信息{std::cout<<_name<<std::endl;std::cout<<_sex<<std::endl;std::cout<<_age<<std::endl;}public://成员变量char _name;char _sex;int _age;
};

3.2.2 定义和声明分开放 

这种方式最常用。

// Person.hclass Person
{public:void showInfo();public:char* _name;char* _sex;int _age;
};
//Person.cpp#include"Person.h"void Person ::ShowInfo()
{std::cout<<_name<<std::endl;std::cout<<_sex<<std::endl;std::cout<<_age<<std::endl;
}

4. 类的访问限定符及封装

4.1 访问限定符

在前面类的定义中,有一个 public ,它属于访问限定符,除了 public(公开)还有 private(私密),protected(保护),它们用于修饰成员,比如 public 修饰的成员可以在类的外面直接被访问,而是用 protected 和 private 修饰的在类的外面不可以直接被访问。

注意以下几点:

  • 访问限定符的作用域是从该访问限定符出现的位置开始直到下一个访问限定符为止 
  • class的默认访问权限(就是没有给出)为 private,struct 则为public
  • 访问限定符限制的是外面,就像锁子防的是外人

 4.2 封装

我们知道面向对象三大特性:封装,继承,多态

封装本质是一种管理手段。将属性(数据)和方法(接口)有机结合起来,再隐藏他们,只对外公开接口(函数)来和对象进行交互。不想给别人看的,使用 protected/private 进行修饰,而开放一些公有函数对成员进行合理访问,合理访问可以理解为阅读,不合理访问可以理解为改写(不准确)

这里也就能说明,为什么C语言不支持大型项目的编写,因为它不支持面向对象,管理能力较弱,不是函数就是数据,就拿 struct 来说,其默认就是 public 的,安全性也堪忧,总的来说,用C语言编写项目,会感觉很乱,模块与模块独立性很差。

之前使用C语言实现过很多数据结构,比如说栈,我们都是新建一个工程然后分别建立它的声明。实现等文件,也就是说数据和方法是分离的,是自由的,如果换到C++中,按照面向对象考虑,一个栈就可以作为一个对象,这个对象有它的数据(动态增长的数组,长度,容量),还有它的方法(栈的初试线,压栈。出栈等等)。像这些数据,应该就是私有的,因为要防止外部操作改变数据,一旦数据出错,那么方法也就会受到相应的波及,然后这些操作按照实际需求让外部使用。

如:

//stack.h
class Stack //类
{
public:void Init(int capacity=4); //缺省参数,声明private:int *_arr;int _length;int _capacity;};//stack.cpp
void Stack::Init(int capacity)//该方法的实现
{_arr=(int *)malloc(sizeof(int )*capacity);_length=0;_capacity=capacity;
};

5. 类的实例化

5.1 类的实例化

类可以理解为一个房屋的图纸,这个图纸规定了一些基本信息,比如说这个房子朝向是什么。有几扇庶户。房子材料是什么等等。但是图纸终归就是图纸,纸上谈兵永远不会成为现实,要把这个图纸现实化,就要根据这个图纸的规定,修出相应的房子。当然,不按照图纸也能修,只不过修出来的房子可能成为四不像,或者不安全。这也就像C语言,没有图纸,接口随意写,数据任你改,是很自由,但是稍有不慎,房子就可能用不久了。

所以说根据图纸建造房子的过程,称为类的实例化,就像前面的栈一样,实例化出一个真正的栈,什么叫做真正的栈--这个栈它占用实际空间。一个图纸不可能只能造出一个房子,而是可以造出千千万万个房子,这个诸多房子本原都是一个,要想让他们之间有所区别,这取决于使用者,比如你和我都按照这个图纸了建造了相同的房子,但是我们对房子的装饰不同,所以看起来也就像两个不同的房子。回到栈,我们可以实例化出许许多多的栈,但是有些栈用于进行非递归操作,有些栈用于排序操作,他们就不是一样的了。

比如前面的栈可以实例化为:

//stack.h
class Stack //类
{
public:void Init(int capacity=4); //缺省参数,声明private:int *_arr;int _length;int _capacity;};//stack.cpp
void Stack::Init(int capacity)//该方法的实现
{_arr=(int *)malloc(sizeof(int )*capacity);_length=0;_capacity=capacity;
};//test.cpp
int main()
{Stack stack;stack._arr=4;//操作非法,成员是 privatae 的stack.Init();//初始化这个栈
}

6. 类对象模型

6.1 如何计算类对象的大小

下面这个类实例化后所占的空间大小:

class A
{
public:void print A{std::cout<<a<<std::endl;}private:char _a;
};

猜测:结合之前学习C语言学习结构体内存对齐,这个类中成员变量和成员函数,其中 char 占用一个字节,成员函数实际是一个函数地址,所以在32为平台下,一个指针占用4个字节,所以总共是5个,然后根据内存,然后占用8个,究竟是不是这样,可以执行。

结构显示只有一个字节,不是预想的8个字节,再次观察这个类,也能想到类在计算大小时不管成员函数只管成员变量和内存对齐。

那么成员函数究竟在哪?

6.2 类对象的储存方式

根据以上叙述,不禁会提出一个问题:为什么成员函数不在类内?

其实:一个类可以实例化很多对象,就拿栈来说,这些栈它储存的数据可能不一样,但他们的方法进栈出栈都是一样的,所以在实例化时,如果为他们再开辟空间,就会造成浪费

以解决方法是:只保存成员变量,成员函数存放到公共的代码段内(常量区)

  • 注意:一般情况下,一个类的大小 ,实际就是该类中成员变量和成员对齐,但是要注意空类,空类大小不是0,编译器提供了一个字节表示它存在。

7. this指针

7.1 一个问题

定义一个日期类

class Date
{public:void SetDate(int year,int month,int day){_year=year;_month=month;_day=day;}private:int _year;int _month;int _day;
}int main()
{Date d1;Date d2;d1.SetDate(2021,2,20);d2.SetDate(2024,7,10);
}

上述代码中看起来没有问题。但是容易忽略一个细节,类中成员函数是公用的,它并不存在于类中,那么 d1.SetDate(2021,2,20),编译器怎么会知道要给d1这个类去设置,而不会给d2去设置。这里很多有疑问,不是函数前面已经写了一个 d1 吗,这里大家一定要跳出这个误区,函数只是放在了公用的代码段,如果函数是放在类里的,那无可厚非。但是当放在公用的代码段后,不要说用实例化的类去调用它,就是我先如果知道函数的地址的话,用汇编都可以去调用,那么当无数个类去调用这个函数时,编译器怎么会分的这么清楚。

7.2 this指针 

这个问题在C++中,是通过引入this指针来解决的。官方定义:C++编译器给每个非静态的成员函数增加了一个隐藏的指针参数。让该指针指向当前函数(运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针操作。

所以如果上述代码,写完整应该是下面这样的

class Date
{public:void SetDate(Date* this,int year,int month,int day){//生成一个类指针this->_year=year;this->_month=month;this->_day=day;//通过指针的指向来辨别对象}private:int _year;int _month;int _day;
}int main()
{Date d1;Date d2;d1.SetDate(&d1,2021,2,20);d2.SetDate(&d2,2024,7,10);//所以参数里实际就是函数的指针
}

7.3 this指针存在那里?

这是一个极高频率的面试题

谈及C、C++的内存开辟,就不得不上这样一张图了

this指针是作为一个函数隐藏的形参,而栈是存放局部变量,形参的。所以,this指针存在于栈中。还有一个经典的题,如下这段程序是否会崩溃

class A
{public:void printA(){    std::cout<<_a<<std::endl;}void show(){std::cout<<"show"<<std::show;}private:int _a;};int main()
{A*p=NULL;p->printA();p->show();
}

这段程序的结果是,如果只执行 p->printA() 就会崩溃,如果只执行 p->show() 就不会崩溃。

如下:

仔细分析,未免让人觉着有点匪夷所思, A* p=NULL ,表明p是一个空的类指针,那么既然是空的就不能对空指针进行操作,但是观察上述两种情况, p→printA()报错了, p→>show()并没有报错。其实原因就是在于这this指针,首先对于 show()和 printA()来说,他们不存在与类内,而存在于公共的代码段内,所以使用指针 ρ 进行这样的操作,并不是在取成员,所以问题不在于空指针。

问题在于:调用 printA() 时,将这个 p 指针作为 this 指针传了过去,那么在函数中就会进行std::cout<<this→_a<<std::endl;的操作,自然而然会出现问题,而另一个函数没有崩溃是因为它就没有使用到这个 this 指针。


这篇文章对类和面向对象的相关知识点进行了梳理。欢迎大家评论交流

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

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

相关文章

apple watch程序出错 Cannot launch apps while in nightstand mode

开发的时候运行apple watch程序出错&#xff1a; ailure Reason: The request was denied by service delegate (IOSSHLMainWorkspace) for reason: Busy ("Cannot launch apps while in nightstand mode"). 这是因为&#xff1a; 将Apple Watch放在充电器上并直立…

.net C# 使用网易163邮箱搭建smtp服务,实现发送邮件功能

功能描述&#xff1a;使用邮箱验证实现用户注册激活和找回密码。邮箱选择网易163作为smtp服务器。 真实测试情况&#xff1a;第一种&#xff1a;大部分服务器运行商的25端口默认是封禁的&#xff0c;可以联系运营商进行25端口解封&#xff0c;解封之后可以使用25端口。第二种&…

matlab R2016b安装cplex12.6,测试时cplex出现出现内部错误的解决方法

问题场景 网上搜索matlabyalmipcplex的安装教程&#xff0c;跟着步骤操作即可&#xff0c;假如都安装好了&#xff0c;在matlab中测试安装是否成功&#xff0c;出现以下问题&#xff1a; 1、matlab中设置路径中添加了yalmip和cplex路径&#xff0c;在命令窗口中输入yalmiptest…

视频号矩阵系统源码,实现AI自动生成文案和自动回复私信评论,支持多个短视频平台

在当今短视频蓬勃发展的时代&#xff0c;视频号矩阵系统源码成为了自媒体人争相探索的宝藏。这一强大的技术工具不仅能帮助我们高效管理多个短视频平台&#xff0c;更能通过AI智能生成文案和自动回复私信评论&#xff0c;为自媒体运营带来前所未有的便利与效率。 一、视频号矩…

Xshll连接服务器【过程记录】

背景&目标 开学老师提供了一款服务器&#xff0c;可以网页端打开&#xff0c;但是不可进行上传文件、复制黏贴指令。 希望连接Xshll进行更有效的学习活动&#xff01; 配置过程 一、已知信息 二、配置 使用第一部分&#xff0c;先打通隧道。 【选择公钥时&#xff0c;没…

CTF php RCE (四)

0x08 取反以及异或、或 这两个东西呢相当的好玩&#xff0c;也能够达到一下小极限的操作 <?php error_reporting(0); if(isset($_GET[code])){$code$_GET[code];if(strlen($code)>40){die("This is too Long.");}if(preg_match("/[A-Za-z0-9]/",$…

【游戏客户端】大话slg玩法架构(二)背景地图

【游戏客户端】大话slg玩法架构&#xff08;二&#xff09;背景地图 大家好&#xff0c;我是Lampard家杰~~ 今天我们继续给大家分享SLG玩法的实现架构&#xff0c;关于SLG玩法的介绍可以参考这篇上一篇文章&#xff1a;【游戏客户端】制作率土之滨Like玩法 PS&#xff1a;和之前…

Linux+InternStudio 关卡

ssh连接 端口映射 本地

FlashAttention/ PagedAttention原理,大模型加速

1.1 GPU 硬件特点 由于 FlashAttention 计算 self-attention 的主要关键是有效的硬件使用&#xff0c;所以了解GPU内存和各种操作的性能特征是很有必要的。 以 A100 (40GB HBM) 为例&#xff0c;下面显示其内存层次结构的粗略图。SRAM内存分布在108个流式多处理器(SMs)上&…

基于 BERT 的非结构化领域文本知识抽取

文章目录 题目摘要方法实验 题目 食品测试的大型语言模型 论文地址&#xff1a;https://arxiv.org/abs/2103.00728 摘要 随着知识图谱技术的发展和商业应用的普及&#xff0c;从各类非结构化领域文本中提取出知识图谱实体及关系数据的需求日益增加。这使得针对领域文本的自动化…

千呼新零售2.0-OCR图像识别采购单视频介绍

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…

2024年公司加密软件推荐TOP10|公司最佳数据防泄密方案!

在当今数字化信息爆炸的时代&#xff0c;保护公司的数据免受泄密威胁至关重要。选择一款适合的加密软件不仅可以有效防止数据泄露&#xff0c;还能保障公司的商业机密和客户隐私。 1.固信软件 固信软件以其卓越的数据保护功能和可靠的安全性而著称。它采用先进的数据加密技术&…

springboot农产品商城-计算机毕业设计源码46732

摘 要 随着社会经济的发展和人们消费观念的升级&#xff0c;农产品电商行业逐渐壮大。但传统的农产品销售模式存在信息不透明、中间环节复杂等问题&#xff0c;而微信小程序作为一种便捷的移动应用平台&#xff0c;为农产品商城的建设提供了新的可能性。通过微信小程序的设计与…

九.核心动画 - 显式动画

引言 本篇博客紧接着上一篇的隐式动画开始介绍显式动画。隐式动画是创建动态页面的一种简单的直接的方式&#xff0c;也是UIKit的动画机制基础。但是它并不能涵盖所有的动画类型。 显式动画 接下来我们就来研究另外一种动画显式动画&#xff0c;它能够对一些属性做指定的动画…

常用知识碎片 Vue3 ref和reactive (内含其他常用知识)

目录 ref和reactive ref reactive 总结&#xff1a; setup语法糖 语法糖是啥&#xff1f; Vue3 setup语法糖 Vue3 不使用setup语法糖示例&#xff1a; Vue3 使用setup语法糖示例&#xff1a; ref和eative主要区别 ref和reactive 在 Vue 3 中&#xff0c;ref 和 reac…

品牌渠道管控力度的平衡艺术

渠道管控力度要如何把握呢&#xff1f;是不是管控越严格就一定越好&#xff1f;例如&#xff0c;发现一次低价就处以高额罚款&#xff0c;发现一次窜货也重罚&#xff0c;其实处罚是对低价管控较为直接的一种方式&#xff0c;但并非处罚越重就一定能取得良好的管控效果。 比如品…

Java 中的 switch 语句:类型支持与限制

Java 中的 switch 语句&#xff1a;类型支持与限制 1、switch 语句支持的数据类型2、switch 语句不支持的数据类型3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在 Java 中&#xff0c;switch 语句是一种用于多分支选择的控制结构…

如何使用FreeFileSync:一款免费且专业的数据备份与文件同步软件

数据的重要性不言而喻&#xff0c;因此&#xff0c;定期做数据备份已经是每一个人的基本工作习惯了。 FreeFileSync 是一款强大专业且免费开源的 文件夹对比/同步/备份 软件工具。FreeFileSync通过比较其内容&#xff0c;日期或文件大小上的一个或多个文件夹&#xff0c;然后根…

统信UOS桌面操作系统上删除系统升级后GRUB中的回滚条目与备份

原文链接&#xff1a;统信UOS删除升级后GRUB中的回滚条目与备份 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在统信UOS桌面操作系统上删除系统升级后GRUB中的回滚条目与备份的文章。在进行系统升级后&#xff0c;GRUB引导菜单中可能会出现多个回滚条目和备份…

nginx正向代理、反向代理、负载均衡

nginx.conf nginx首要处理静态页面 反向代理 动态请求 全局模块 work processes 1; 设置成服务器内核数的两倍&#xff08;一般不不超过8个超过8个反而会降低性能一般4个 1-2个也可以&#xff09; netstat -antp | grep 80 查端口号 *1、events块&#xff1a;* 配置影响ngi…