类和对象-类基础详解

C++面向对象编程基础:类、成员、this指针与访问控制,
本文详细介绍了C++中的面向对象编程概念,包括类的基础、数据和方法的结合、this指针的作用以及成员变量和成员函数的访问规则。文章强调了类的实例化、访问权限的区别以及如何正确使用this指针,有助于理解面向对象编程的核心原理。

一、面向对象和面向过程编程

1.1 基本理解

C语言:面向过程,关注过程,要求解决问题的步骤,通过函数调用解决问题。
C++:面向对象,关注对象,将解决一件事情分成不同的对象,考对象之间的交互完成。

C语言对应的“关注过程”,指的是通过函数来解决问题。
而C++对应的“关注对象”,指的是通过类来解决问题。
解决一个问题肯定是需要明确是谁做的,通过什么方法做的,C语言的方式是谁做的和通过什么方法完成的两者分开,而C++通过类将解决问题的方法内置到了对象身上,所以就可以通过对象间的交互来解决问题了🌴。
在这里插入图片描述

  1. C语言解决问题的方法是函数。比如上面的洗衣服,烘干衣服和晾衣服的问题,我们需要【洗衣服函数】,至于到底是谁在洗衣服(谁调用的洗衣服函数),函数并不在乎,可以是【人】,也可以是【洗衣机】,这要求我们解决一个问题时既要关注【人】or【洗衣机】,又要关注【洗衣服函数】or【烘干衣服函数】or【晾衣服函数】🌳。
  2. C++解决问题的方法是类。比如上面的衣服,烘干衣服和晾衣服的问题,只需要两个对象:【人】【洗衣机】,人有【洗衣服(函数)】,【晾衣服(函数)】的功能,洗衣机有【洗衣服(函数)】,【烘干衣服(函数)】的功能,这些功能内置了,解决问题时只需要两个对象相互配合就行,不需要我们再自己搭配让谁去干什么,它们自己就可以完成,因为它们内置了那些功能🌷。

1.2 主要方面

面向过程和面向对象,区别主要体现在类的设计上。

C语言的结构体和C++的类的结构有相似之处,也有不同之处。

1.2.1 数据和方法分离

C语言的结构体的数据和方法是分离的,而C++的类的数据和方法是在一起的。
在这里插入图片描述

  1. C语言的数据和方法分离,将函数写到外面,对于不同的数据结构如 Stack ,Queue 等都需要 Push() 等函数,但如果都命名为 Push() ,就很难区分是哪种结构的Push() 了,而且 C语言不支持同名函数;🥝
  2. 因为C语言数据和方法分离,所以结构体调用函数时,必须写参数,不然无法找到数据。

1.2.2 C++兼容C语言

C++兼容 C语言struct 的所有用法,struct 同时升级成了类。
此处的兼容,并不是指C++中又有类,又有结构体,C++中只有类,没有结构体,所以说是结构体升级成了类
由于C++中只有类,所以C语言的结构体转移到C++环境中时就会转变成类,从表面上看就是C++兼容结构体,但实际上是类兼容了结构体的写法。🥕

类与结构体的不同:
①类名就是类型,上面 Stack 就是类型,不需要加 struct
②类里面可以定义函数

二、类基础

在这里插入图片描述
从上图可知,下面要说的几个方面。

2.1类的格式

在这里插入图片描述

  1. struct 和 class 定义类都可以,用法上完全相同,只是在访问权限上稍有差异,下面会提及。
  2. 这样做是为了兼容 C语言的结构体,因为C语言的结构体就是用 struct 定义的,所以要兼容的话,类必须也可以用 struct 定义。🥗

2.2 类的成员

类体中的内容称为类的成员
类中的变量称为类的属性成员变量
类中的函数称为类的方法成员函数

2.3 域

C++ 中 { } 定义的都是域。

2.4 访问限定符

类中的访问限定符有 3 个:public(公有的),private(私有的),protected(保护)。🐍

2.4.1 特点

  1. pbulic 修饰的成员可以在类外直接被访问,private 和 protected 修饰的成员在类外不能直接被访问
  2. 访问权限的作用域是从该访问限定符出现的位置开始直到下一个访问限定符出现为止,如果后面没有访问限定符,作用域就到 } 结束。🥳

在这里插入图片描述

2.4.2 class 和 struct 默认访问权限不同:

在这里插入图片描述

  1. class 声明的类,如果没有访问限定符,那成员(包括成员变量和成员函数,上图只展示了成员变量,但成员函数也是一样的道理)默认就会是私有的,而 struct 声明的类,会默认是公有的
  2. 这样做是为了==兼容结构体 struct == ,C语言中的结构体是没有私有这一说的,所有成员外部都是可以访问的,所以为了让 struct 定义的结构体可以顺利地在 C++ 环境下使用,C++中的 struct 声明的类默认必须为公有。💯
  3. 我们提倡明确使用访问限定符,这样可读性比较高。

2.4.3 访问限定符存在的必要性:

访问限定符是为了限制C语言的结构体的内部数据被外面访问的状态。💭
比如说判断一个栈空间是否为空,用结构体声明的栈,可以通过下面两种方式来判断:
在这里插入图片描述
但如果我们用的是别人的代码,别人设计的栈,我们凭什么认为 top 为 0 时,栈就为空了呢,万一人家设计的是 top 为 -1 时,栈才为空呢,所以这样直接访问 top 是有风险的。 🌷
当我们使用类时,用限定符将成员变量 top 限制为 private,就只能使用 Stack_Empty() 来判断了,较为安全。

2.5 类的成员变量的命名

2.5.1 为什么成员变量用特别的命名形式?

在这里插入图片描述

可以正常运行,但并不能区分形参和成员变量,而且上述 Init () 函数并没有起到初始化类对象的作用。
实际上函数中的两个 year 都是形参year,而不是成员变量year ,因为有局部优先原则,两个 year 都会是形参,而不是成员变量 year。🌿

在这里插入图片描述

所以,会将成员变量的命名取的特殊一些,以便与其他命名分开。

2.5.2 怎样命名成员变量?

最常用的是在成员变量的名称前加 _,如下:

在这里插入图片描述
不同的公司可能会有不同命名习惯,如下:

在这里插入图片描述

2.6 成员函数的声明和定义分离

在这里插入图片描述

  1. 分离:指的是成员函数定义写在了类外;注意要在函数前标明类域
  2. 未分离:指的是成员函数直接在类中定义;默认直接在类中定义的函数是内联函数
  3. 正确的用法:短小的函数可以直接在类内定义,较长的函数就声明和定义分离。🍃

三、类的实例化

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

在这里插入图片描述

3.1 对象的声明和定义

开空间的地方是定义,言明类型的是声明。

在这里插入图片描述

3.2 类的大小

在计算类的大小时,只考虑成员变量,不考虑成员函数。

每个对象的成员变量不同,但它们的函数时一样的,如果每个对象都单独拥有自己的成员函数,那就会有很多不同的函数地址,没有必要,既然大家用的都是同样的函数,那就写一个公有的好了,谁用的就传谁的参数进去。🍎

在这里插入图片描述

3.2.1 存储结构

一个类对象中只存储成员变量,不存储成员函数
成员变量存放到具体的对象中,成员函数会统一存放到类的公共代码区。🍑
在这里插入图片描述

成员函数的属于和存储问题
  1. 属于:非静态成员函数属于具体的对象,必须要有对象,才能调用;静态成员函数属于类,不用对象也能调用。

在这里插入图片描述
2. 存储:成员函数属于对象,但并不存储于对象,存储于公共代码区。🥕

在这里插入图片描述

3.2.2 空类的大小

空类:没有成员变量的类。(因为成员函数并不存储于具体的类对象中,所以及时有成员函数,仍然是空类)

在这里插入图片描述

  1. 没有成员变量的类,对象大小开一个字节,这个字节不存储有效数据,只标识定义的对象存在过。
  2. 空类对象大小不能设置成 0,如果设计成 0,那 &d1,&e1 就没有空间地址了,不合适。🍏
    在这里插入图片描述

四、this 指针

4.1 this 指针为什么存在?

成员函数作用于具体的对象,而不是图纸,所以成员函数要与具体的对象联系起来。🦐

在这里插入图片描述
所有成员函数是所有成员公用一份的,调用函数时,函数怎么定位到一个具体的对象身上呢?—— 通过一个指向对象的指针,这个就是 this 指针。

在这里插入图片描述

4.2 this 指针在什么地方?

4.2.1 this 在函数中的位置

  1. 成员函数也是函数,想要作用对应的对象,需要传对象到函数,所以 this 指针在形参的位置上。🥝
  2. 因为总要传 this 指针,而且传的东西固定,就是调用函数的对象的地址,所以这个过程可以自动化,就交给编译器处理了,所以就出现了没有看见 this 指针的情况。
    在这里插入图片描述
  3. 调用成员函数时,编译器进行了处理,默认:成员函数的第一个参数是对应的对象的 this 指针。在这里插入图片描述
  4. 与C语言结构体函数相比,this 就相当于 p,本质上是相同的,但 C++ 中这个过程让编译器承担了。🌲
    在这里插入图片描述

4.2.2 this 在内存中的位置

  1. this 属于形参,存储在中。
  2. VS环境下,将 this 存到了寄存器中。
    一些小的、常用的量,编译器会把它们存到寄存器中,速度快。🥭

在这里插入图片描述

4.3 this 的使用注意事项

4.3.1 this 指针不能修改

因为 this 指针的作用是让成员函数可以作用具体的对象,如果我们把 this 指针的指向改动了,就没办法找到函数作用的对象了,当然如果进行了复制等工作,仍然是可以找到对象的,但就比较没必要,所以干脆将 this 的指向固定下来,免得乱动指向造成各种问题。 🌴
在这里插入图片描述

4.3.2 不能显示写 this 相关的实参和形参

  1. 因为编译器已经帮我们在形参和实参位置上默认加上 this 指针了,我们再手动加 this 指针,编译器不会合并,只会看成是两个相同的实参、形参。

在这里插入图片描述

  1. 但可以在函数内部显示使用 this 指针。因为 this 指针就是一个编译器帮我们传过来的一个隐形的形参,是形参就可以使用,所以内部可以显示使用 this 指针。🍒

在这里插入图片描述

五、成员变量和成员函数的访问

5.1 访问情况详解

访问公有的成员变量和成员函数,可以使用类类型的对象和指针,如下所示。

在这里插入图片描述
但如果类指针是一个空指针,那它对成员的访问就有限制了。💦
空指针:
访问/使用空指针是可以的,但不能访问/使用空指针指向的内容,因为空指针没有指向内容,所以不能访问,一旦你访问了,就会报错。

在这里插入图片描述

  1. 访问成员变量:🧊访问的逻辑是访问指针指向的对象的成员变量。
    因为成员变量存储于每个对象中,要想访问成员变量必须得有对象,但空指针没有指向某个存在的对象,既然没有存在的对象那就无法完成访问逻辑,无法访问成员变量。(没有指向对象,那就是没有对象,都没有对象,还访问谁的变量啊 🌷)
  2. 访问成员函数:🧊访问的逻辑是调用成员函数,其中参数传的是指针指向的对象。
    因为成员函数并不存储于每个对象中,是所有对象共用的一份代码,所以即使没有对象,成员函数仍然存在。类指针会指向一个对象,所以可以间接代表一个对象的存在,可以给成员函数传参数,所以类指针是可以调用成员函数的,即使是空指针,那也仅仅代表着要将空指针传给函数做参数,是可以的,这里只是用了 nullptr 而已,并没有要访问 nullptr 指向的内容,所以不会报错。如上述的 Print()函数。🍊
    但是,如果函数中有要访问 nullptr 指向的内容的,即要访问属于具体对象的成员变量,是不行的,因为没有对象,所以也没有成员变量给你访问。如上述的 Init()函数。🌳
  3. 编译器的优化:如果只是写一下,并没有要访问、修改之类实质性的动作,本来也是不可以的,但编译器进行了优化,允许这样而不报错。

在这里插入图片描述

5.2 总结如下:🌵

在这里插入图片描述

类基础详解到这里就结束了,如果对您有帮助的话,不奢求您的关注,但希望您可以给点个赞,您的支持对我非非非常有帮助!!!🧡
如果有哪里说的不对或不好的地方,请您一定要告诉我(私信也好,评论也好),我一定虚心请教改正,最后感谢您看到这篇文章🌷。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值