【C++】什么是类与对象?

🦄个人主页:修修修也

🎏所属专栏:C++

⚙️操作环境:Visual Studio 2022


目录

面向对象概述

       封装

       继承

       多态

类是什么?

C++中类的引入

C++中类的定义

类的两种定义方式:

1.声明和定义全部放在类体中

2.类声明与成员函数定义分别放在不同的工程文件中:

类的访问限定符

类的封装

类的作用域

类的实例化

类对象模型

如何计算类对象的大小

类对象存储方式

结语


面向对象概述

        面向对象是一种符合人类思维习惯编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。
        对于学习过其他编程语言的人员来说,可能会想到面向过程。面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一一实现,使用的时候依次调用就可以了。面向对象则是把构成问题的事物按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。当然,一个应用程序会包含多个对象,通过多个对象的相互配合即可实现应用程序所需的功能,这样当应用程序功能发生变动时,只需要修改个别的对象就可以了,从而使代码更容易维护。
        面向对象的特点可以概括为封装继承多态,接下来针对这三种特性进行简单介绍。

       封装

            封装是面向对象的核心思想,将对象的属性和行为封装起来,不需要让外界知道具体实现细节,这就是封装思想。例如,用户使用计算机,只需要使用手指敲键盘就可以了,无须知道计算机内部是如何工作的,即使用户可能碰巧知道计算机的工作原理,但在使用时,并不完全依赖计算机工作原理这些细节。

       继承

            继承主要描述的就是类与类之间的关系,通过继承,可以在无须重新编写原有类的情况下,对原有类的功能进行扩展。例如,有一个汽车的类,该类中描述了汽车的普通属性和功能。而轿车的类中不仅应该包含汽车的属性和功能,还应该增加轿车特有的属性和功能,这时,可以让轿车类继承汽车类,在轿车类中单独添加轿车特有的属性和功能就可以了。继承不仅增强了代码的复用性,提高了开发效率,还为程序的维护补充提供了便利。

       多态

            多态指的是在一个类中定义的属性和功能被其他类继承后,当把子类对象直接赋值给父类引用变量时,相同引用类型的变量调用同一个方法所呈现出的多种不同行为特性。例如,当听到cu这个单词时,理发师的行为表现是剪发,演员的行为表现是停止表演等。不同的对象,所表现的行为是不一样的。


类是什么?

  • 类是面向对象语言的程序设计中的概念,是面向对象编程的基础。
  • 类的实质是一种引用数据类型,类似于 byte、short、int(char)、long、float、double 等基本数据类型,不同的是它是一种复杂的数据类型。因为它的本质是数据类型,而不是数据,所以不存在于内存中不能被直接操作只有被实例化为对象时才会变得可操作
  • 类是对现实生活中一类具有共同特征的事物的抽象。如果一个程序里提供的数据类型与应用中的概念有直接的对应,这个程序就会更容易理解,也更容易修改。一组经过很好选择的用户定义的类会使程序更简洁。此外,它还能使各种形式的代码分析更容易进行。特别地,它还会使编译器有可能检查对象的非法使用。
  • 类的内部封装了属性和方法,用于操作自身的成员。类是对某种对象的定义,具有行为(behavior),它描述一个对象能够做什么以及做的方法(method),它们是可以对这个对象进行操作的程序和过程。它包含有关对象行为方式的信息,包括它的名称属性、方法事件
  • 类的构成包括成员属性成员方法数据成员成员函数)。数据成员对应类的属性,类的数据成员也是一种数据类型,并不需要分配内存。成员函数则用于操作类的各项属性,是一个类具有的特有的操作,比如“学生”可以“上课”,而“水果”则不能。类和外界发生交互的操作称为接口。

C++中类的引入

        C语言结构体中只能定义变量,比如:之前在数据结构中,我们用C语言方式实现的栈,结构体中只能定义成员变量:

【数据结构】C语言实现顺序栈(附完整运行代码)

//C语言中定义顺序栈的结构体struct Stack
{int *arr;int top;int capacity;
};

        并且,在C语言中,我们创建的结构体变量,只能访问自己的成员变量:

        而在C++中,结构体内不仅可以定义成员变量,也可以定义函数。现在我们以C++方式实现栈,可以发现struct中也可以定义函数:

struct Stack
{void Init(size_t capacity){_arr = (int*)malloc(sizeof(int) * capacity);if (nullptr == _arr){perror("malloc申请空间失败");return;}_capacity = capacity;top = 0;}//成员变量的位置可以是类内的任意地方int *arr;int top;int capacity;
};

        并且,在C++中,我们创建的结构体变量,是可以访问结构体成员函数的:


C++中类的定义

        虽然C++因为兼容C语言的缘故,将C语言中的struct升级为了类,但实际应用中,C++更喜欢使用class关键字来声明类。class 声明类时格式如下:

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

        class为定义类的关键字,class_name类的名字,{}中为类的主体,注意类定义结束后最后的分号不能省略

        类中的内容称为类的成员:类中的变量称为类的属性成员变量,类中的函数称为类的方法或者成员函数.

类的两种定义方式:

1.声明和定义全部放在类体中

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

class Stack
{
public:void Init(size_t capacity){_arr = (int*)malloc(sizeof(int) * capacity);if (nullptr == _arr){perror("malloc申请空间失败");return;}_capacity = capacity;_top = 0;}public://成员变量的位置可以是类内的任意地方int* _arr;int _top;int _capacity;
};

注意:为了防止在类中定义函数时像下面这样容易使成员变量函数参数混淆:

一般当声明和定义全部放在类体中时我们会将类中的成员变量名前面加_以示区分:

2.类声明与成员函数定义分别放在不同的工程文件中:

类声明放在.h文件中:

成员函数定义放在.cpp文件中,注意:成员函数名前需要加  类名::


类的访问限定符

        C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。

访问限定符的特性:

  • public修饰的成员在类外可以直接被访问
  • protectedprivate修饰的成员在类外不能直接被访问(此处protectedprivate是类似的)。
  • 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  • 如果后面没有访问限定符,作用域就到 } 即类结束。
  • class默认访问权限为privatestruct为public(因为struct要兼容C)。

注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

C++中struct和class的区别是什么?
        C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。在继承和模板参数列表位置,struct和class也有部分区别。


类的封装

        我们在文章一开始就介绍了面对对象的三大特性:封装,继承,多态

        封装是面向对象的核心思想,将对象的属性和行为封装起来,不需要让外界知道具体实现细节,这就是封装思想。

        封装本质上是一种管理让用户更方便使用类。比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。
        在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节控制哪些方法可以在类外部直接被使用

        在C语言中,由于对结构体没有封装的概念,从而会导致使用者通过变量对结构体中的成员变量进行任意不合规的操作。

        如下,在栈程序中,使用者就没有通过取栈顶元素函数获取栈顶元素,而通过直接访问成员变量的方式访问了栈顶元素:

        而在C++中,我们可以通过访问权限来隐藏对象内部实现细节控制哪些方法可以在类外部直接被使用,而哪些方法在类外部不可以被使用。


类的作用域

        类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员(包括变量和函数)时,需要使用 :: 作用域操作符指明成员属于哪个类域。

        如,上文中在C++中类的定义方式中我们提到的:

        有关类的作用域,有以下几点需要注意:

  • 局部域,全局域,命名空间域,类域,不同的域中可以定义同名变量。
  • 类中的变量查找优先级:局部域>类域>全局域/命名空间域(非指定展开则不查找)。
  • 局部域和全局域会影响生命周期,类域和命名空间域不会影响生命周期。

类的实例化

            用类类型创建对象的过程,称为类的实例化

  1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类但并没有分配实际的内存空间来存储它;比如:入学时发放的学生信息表,表格就可以看成是一个类,来描述具体学生信息。但在还没有学生填表时,这个表格就并没有实际存储学生的任何信息。
  2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量。
  3.        打个比方来说,上面这个例子中的Date就类似于一个房屋建造的图纸,它规定了这个房屋建造多高,多宽,多长,以及各个地方的设计细节。但你如果不真正的将房子按照图纸建造出来,你就永远无法将家具之类的东西搬进房子里住,上图中使用Date类直接存储_year的数据就类似于要将现实世界的床搬进房屋设计图纸里住人。

类对象模型

如何计算类对象的大小

        在C语言中,我们学习过如何使用sizeof操作符计算结构体的大小,以及如何通过结构体对齐规则去计算结构体的大小(还不太了解的朋友可以移步这篇博客):

【C语言】结构体的大小是如何计算的?(结构体对齐)icon-default.png?t=N7T8https://blog.csdn.net/weixin_72357342/article/details/131135555?spm=1001.2014.3001.5502

        在C++中,对类的大小计算我们同样是使用sizeof操作符,如下例子,我们使用sizeof操作符分别计算Date类和Date类对象Birthday的大小:

class Date
{
public:void InitDate(int year, int mouth, int day){_year = year;_mouth = mouth;_day = day;}
public:int _year;int _mouth;int _day;
};int main() {Date Birthday;Birthday._year = 2000;int sz1 = sizeof(Date);int sz2 = sizeof(Birthday);printf("%d %d\n", sz1, sz2);return 0;
}

        运行查看结果,可以看到,类的大小和类对象的大小是一致的,这和结构体与结构体变量的大小计算结果一致:


类对象存储方式

        在知道了如何使用sizeof操作符计算类的大小后,我们还需要探究一下类对象究竟在内存中是怎样存储的。

        在C语言中,结构体的大小是由成员变量构成的,这我们很好理解,但在C++中,类的大小计算起来却看起来复杂的多,因为类中不仅包含了成员变量,还包含了成员函数,它们是如何存储在内存中的?它们和成员变量的关系又是怎样的?下面我们一起来探究一下:

`        如下,我们分别构建了一个类对象Date1,以及一个结构体对象Date2,分别计算他们的大小以及由它们创建的变量Birthday1,Birthday2的大小:

class Date1{
public:void InitDate(int year, int mouth, int day){_year = year;_mouth = mouth;_day = day;}
public:int _year;int _mouth;int _day;
};struct Date2{int year;int mouth;int day;
};int main() {Date1 Birthday1;Birthday1._year = 2000;int sz1 = sizeof(Date1);int sz2 = sizeof(Birthday1);printf("%d %d\n", sz1, sz2);Date2 Birthday2;Birthday2.year = 2000;int sz3 = sizeof(Date2);int sz4 = sizeof(Birthday2);printf("%d %d\n", sz3, sz4);return 0;
}

运行程序,我们可以发现,它们的大小是一样大的:

        也就是说,类的大小是不包含成员函数的大小的,它的大小只取决于类中的成员变量.同样的,类对象的大小也仅取决于成员变量的大小.

        这样的存储策略其实并不难理解,打个比方说,如果我们将类比作一个小区,那么类对象中的成员变量就类似于一间一间的居民楼,供用户存放个人的物品使用,而类中的成员函数则类似于小区中的凉亭或健身器材区域,它是可以提供给所有小区中的人使用的,并且所有人使用它都是一样的,因此完全不需要给每家都修一个,而是可以整个小区只修建一个,大家一起使用就可以了。

        因此,我们可以推断出,类成员的存储方式应该类似于下图这种结构:

        下面我们设计几个类来验证一下我们的推断:

//类中既有成员变量也有成员函数
class Date1 {
public:void InitDate(int year, int mouth, int day) {_year = year;}
public:int _year;int _mouth;int _day;
};//类中只有成员函数
class Date2 {
public:void InitDate(int year, int mouth, int day) {year=2000;}
};//类中只有成员变量
class Date3 {
public:int _year;int _mouth;int _day;
};//类中什么都没有
class Date4 {};int main() {int sz1 = sizeof(Date1);int sz2 = sizeof(Date2);int sz3 = sizeof(Date3);int sz4 = sizeof(Date4);printf("%d %d %d %d\n", sz1, sz2,sz3,sz4);return 0;
}

        运行程序,得到结果:

        可以看到,类中既有成员函数也有成员变量和类中只有成员变量的大小是一样的,而类中只有成员函数和类中什么都没有的大小是一样的.

        需要注意的是,在没有成员变量的情况下,类的大小是1,它需要1字节的空间占位,表示对象存在,但不存储任何有效数据。

        需要注意的是,类中的成员变量的计算规则和C语言中的结构体一样,都遵循结构体对齐规则,所以下面这种情况中,Date1类的大小是8而不是5:

        对于结构体对齐规则的详解,感兴趣的朋友可以移步下面这篇博客:

【C语言】结构体的大小是如何计算的?(结构体对齐)icon-default.png?t=N7T8https://blog.csdn.net/weixin_72357342/article/details/131135555?spm=1001.2014.3001.5502


结语

希望这篇关于类与对象的基础博客能对大家有所帮助,欢迎大佬们留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐

【C++】缺省参数(默认参数)

【C++】“Hello World!“

【C++】命名空间


慎在此祝愿全世界伟大的劳动妇女们,节日快乐!

广阔天地,大有作为!

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

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

相关文章

Qt开发QHostInfo主机地址查询组件

Qt 是一个跨平台C图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QHostInfo组件实现对主机地址查询功能…

三井住友保险中国区信息技术部负责人陈婧,将出席“ISIG-RPA超级自动化产业发展峰会”

3月16日,第四届「ISIG中国产业智能大会」将在上海中庚聚龙酒店拉开序幕。本届大会由苏州市金融科技协会指导,企智未来科技(RPA中国、AIGC开放社区、LowCode低码时代)主办。大会旨在聚合每一位产业成员的力量,深入探索R…

用一个 Python 脚本实现依次运行其他多个带 argparse 命令行参数的 .py 文件

🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 问题描述:在 Windows 环境中,您希望通过一个 Python 脚本来实现特定的自动化任务,该任务需要依次运行其他多个带 argparse 命令行参数的 .py 文件。您希望找到一种简…

手写分布式配置中心(六)整合springboot(自动刷新)

对于springboot配置自动刷新,原理也很简单,就是在启动过程中用一个BeanPostProcessor去收集需要自动刷新的字段,然后在springboot启动后开启轮询任务即可。 不过需要对之前的代码再次做修改,因为springboot的配置注入value("…

C++命名空间详解

目录 C的由来: C语言的命名缺陷: 什么是命名空间? 命名空间的访问方式: 1、指定访问 2、展开命名空间(慎用) 相关知识: C的由来: C原来本质上是在C的基础上补充的语法&#x…

ARM单片机中程序在ROM空间和RAM空间的分布(分散加载文件,Scatter-Loading Description File)

对于 K e i l u V i s i o n I D E Keil\quad uVision\quad IDE KeiluVisionIDE,程序编译好之后,代码的下载位置( R O M ROM ROM空间)以及代码运行的时候使用的 R A M RAM RAM空间( R A M RAM RAM空间)默认…

下载一些ROS的包的方式

ROS Index 我们可以去ROS Index网站下载一些我们需要的包。打开浏览器在网址框输入index.ros.org。或者点击此处链接ROS Index 在这个网站中我们可以浏览并找到我们需要的包,也可以下载它的源代码或者仅安装到我们的系统中来使用。(安装过程在终端中进行…

植物病虫害:YOLO水稻虫害识别数据集(6类,五千余张图像,标注完整)

YOLO水稻虫害识别数据集,包含褐飞虱,绿叶蝉,正常叶片,稻虫,二化螟,蝇蛆6个类别,共五千余张图像,yolo标注完整。 适用于CV项目,毕设,科研,实验等 …

零、自然语言处理开篇

目录 0、NLP任务的基础——符号向量化 0.0 词袋模型 0.1 查表/One-hot编码 0.2 词嵌入模型/预训练模型 0.2.0 Word2Vec (0)CBOW (1)Skip-gram 0.2.1 GloVe 0.2.2 WordPiece 0.2.3 BERT 0.2.4 ERNIE NLP自然语言处理&am…

Java 的 System 类常用方法介绍

Java 中的 System 类是一个final类,它提供了与系统相关的属性和方法。它是一个内置的类,可以直接使用,不需要实例化。System 类提供了标准输入、标准输出和错误输出流,以及对外部定义的属性和系统环境的访问。下面是 System 类的一…

LCR 132. 砍竹子 II

解题思路&#xff1a; 由于数量级较大&#xff0c;需要使用long以及快速幂求余 下图便于理解快速幂求余 class Solution {public int cuttingBamboo(int bamboo_len) {if(bamboo_len < 3) return bamboo_len - 1;int b bamboo_len % 3, p 1000000007;long rem 1, x 3;f…

【PHP+代码审计】PHP基础——数据类型

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

012集——显示高考天数倒计时——vba实现

以下代码实现高考倒计时&#xff1a; Sub 高考倒计时() 高考日期 CDate("06,07," & Year(Date)) If Date > 高考日期 Then高考日期 CDate("06-07-" & Year(Date) 1) End If 年月日 Year(Date) & "年" & Month(Date) &am…

Springboot+vue的项目申报管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的项目申报管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09…

低密度奇偶校验码LDPC(九)——QC-LDPC译码器FPGA全并行设计

往期博文 低密度奇偶校验码LDPC&#xff08;一&#xff09;——概述_什么是gallager构造-CSDN博客 低密度奇偶校验码LDPC&#xff08;二&#xff09;——LDPC编码方法-CSDN博客 低密度奇偶校验码LDPC&#xff08;三&#xff09;——QC-LDPC码概述-CSDN博客 低密度奇偶校验码…

蓝牙系列七:开源蓝牙协议栈BTStack数据处理

继续蓝牙系列的研究。 在上篇博客,通过阅读BTStack的源码,大体了解了其框架,对于任何一个BTStack的应用程序都有一个main函数,这个main函数是统一的。这个main函数做了某些初始化之后,最终会调用到应用程序提供的btstack_main,在btstack_main里面首先做一些初始化,然后…

C语言指针——常量字符串和 变量字符串

常量字符串和 变量字符串 常量字符串和变量字符串是在编程中常见的两种字符串类型&#xff0c;它们有以下区别&#xff1a; 值的不可变性&#xff1a;常量字符串的值是不可变的&#xff0c;一旦被定义&#xff0c;就不能修改。而变量字符串的值是可变的&#xff0c;可以随时修…

重建大师6.2版本的建模效果出现下图中模糊的情况,是什么原因?

可能是因为坐标原点设置的不对&#xff0c;图例中的三角网都出现了精度损失的问题。 坐标原点设置的具体操作&#xff1a;提交产品后&#xff0c;在弹出的界面&#xff0c;可以设定坐标原点。 重建大师是一款专为超大规模实景三维数据生产而设计的集群并行处理软件&#xff0…

C语言之练手题

题目1&#xff1a; 思路&#xff1a;我们定义两个变量left和right分别为数组的左端下标和右端下标。 左端下标的元素为奇数时&#xff0c;left继续往前走&#xff0c;为偶数时就停下 右端下标的元素为偶数时&#xff0c;right- -往回走&#xff0c;为奇数时停下 停下后对应的元…

(3)应用与信息

文章目录 前言 3.1 FlightDeck FrSky发射器应用程序 3.2 MAVLink2数据包签名(安全) 3.3 MAVLink高延迟协议 3.4 无线地面站连接中继器 1 概述 2 组件 3 设置 3.5 遥测无线电区域条例 3.6 用于OpenTX的Yaapu遥测脚本 前言 FlightDeck FrSky Transmitter AppMAVLink2 …