栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++类和对象

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++类和对象

目录

1.this指针:

1.1什么是this指针:

1.2this指针存在哪里

1.3this指针可以为空吗?

2.空类里面有什么

3.构造函数

4.析构函数

5.拷贝构造:

6.运算符重载

7.const修饰类的成员函数


1.this指针:

1.1什么是this指针: 我们在调用类中的成员函数时,this指针起的作用是功不可没的,它是每个类中的成员函数的第一个隐形形参。负责将当前调用函数的对象的地址传入。

1.2this指针存在哪里

1.3this指针可以为空吗? 理论上this指针是不可以为空的,因为你指向一个对象的地址然后对这个对象中的成员变量进行操作,但是我们透过现象看本质,类中的函数其实是存在代码区的,因为在计算类的对象的大小时,并不会将函数的大小也算进去,所以我们可以这样理解,在我们调用类中的成员函数时,其实和调用普通的函数是一样的,只是因为他是类中的成员函数,在我们用[对象].[成员函数],调用成员函数时会将调用对象的地址传递给成员函数的隐藏形参this指针,所以类中的成员函数就可以对类中的对象进行操作,而当我们将传入的函数指针为空指针时,我们只要不对函数中的成员变量进行操作是完全可以的。

运行发现可以正常调用函数,运行正常

2.空类里面有什么

不是什么都没有,编译器会给类生成6个默认的成员函数:构造函数,析构函数,拷贝构造,赋值重载,普通对象和const对象取地址重载。

3.构造函数

概念:

对象创建时的初始化工作

特性:

1.构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有 一个合适的初始值,并且在对象的生命周期内只调用一次。没有返回值类型。编译器在创建对象时就会调用一次构造函数,可以看到我们这里只是创建了一个d1对象。

在运行时可以发现系统自动帮我们调用构造函数

2.如果我们不写构造函数编译器就会为我们自动生成构造函数称为默认构造函数

默认构造函数一定是无参的用户一旦定义了构造函数,则编译器就不会生成构造函数3.如果我们自己定义了有参数的构造函数时,那么在定义对象的时候就要向构造函数中传递参数

这里我们向对象中传入与构造函数参数相匹配的参数

或者定义一个无参的构造函数

4.如果我们自己不定义构造函数,编译器就会帮我们构造默认的构造函数但是默认的构造函数,对于对象内的成员变量赋的初始值也只是一个随机值,那么系统创建的默认构造函数有什么用呢?4.1我们接下来看一个场景

我们运行代码发现他将Time类的构造函数也同时运行了,但是我们只创建了一个Date类型的对象,那他为什么会将Time的构造函数也运行出来呢?

我们转到反汇编来看一下

我们进入Date的构造函数当中来可以看到有一条调用Time类构造函数的指令,这就说明,Time类的构造函数是在Date类中调用的

总结:系统为我们创建的默认构造函数会调用类中类型未其他类的对象的调用函数可以通过一张图来理解

5.无参的构造函数和全缺省的构造函数都可以当作默认函数

但是这两个构造函数不能同时存在否则就会报错

4.析构函数

概念:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作特点:1. 析构函数名是在类名前加上字符 ~。2. 无参数无返回值。

3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。

4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。5.如果类的内部有用户自己创建的类,定义的对象,则在调用当前对象的析构函数时会调用用户自己创建的类的析构函数。

如果类中没有申请资源我们是不需要写析构函数的,但是如果要是在类中申请了资源就一定要写析构函数,在析构函数中释放申请的资源。

5.拷贝构造:

概念:

只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰,因为我们的析构函数的作用是将传入的类的成员变量的值传递给当前的成员变量,不可对传入的对象的进行修改),在用已存在的类类型对象创建新对象时由编译器自动调用特性:1. 拷贝构造函数是构造函数的一个重载形式。2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。

3. 若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,或者值拷贝。4.当然浅拷贝是有危害的,如果类中涉及到内存管理就会使代码崩溃,例如我们在堆上申请一块空间,在拷贝一个对象时,会将它指向堆的这个指针内保存的地址也拷贝一份,那么不管是在使用或者释放内存时,都是对同一个堆地址进行操作。这样就会出错。我们下面就模拟这样一个场景

使用场景:

1.使用已存在对象创建新对象

2.函数参数类型为类类型对象

3.函数返回类型为类类型对象

6.运算符重载

概念:C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。使用:函数名字为:关键字operator后面接需要重载的运算符符号。函数原型:返回值类型 operator操作符(参数列表)注意:1.不能通过连接其他符号来创建新的操作符:比如operator@

2.重载操作符必须有一个类类型或者枚举类型的操作数,内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义

3.用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义,像下面这个例子,我们重载”+“不能在内部改为减法

4.作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的操作符有一个默认的形参this,限定为第一个形参

我们将重载函数作为类的成员时,给其设置两个参数,可以发现编译器报错:

当我们只设置一个变量:

5.[ .*] ( 用来调用指向类成员的函数指针)、[:: ](作用域)、[sizeof](长度) 、[?: ](环境条件)、[. ](访问成员)、[#](符号)注意以上5个运算符不能重载。这个经常在笔试选择题中出现使用:我们这里将"=="运算符重载,判断两个日期的大小。可以看到我们能更直观的理解代码含义。

"!="运算符重载

6.赋值运算符"="重载,如果我们自己未对类中定义赋值运算符的重载,编译器会默认帮我们生成一个"="运算符的重载,这个赋值运算符的重载是浅拷贝我们来模拟一个场景:未在类中定义"="的重载,可以发现编译器仍然没有报错

让代码运行起来:我们发现一开始d1中_array和d2中_array的地址都不同。

执行赋值语句之后,发现发生浅拷贝,d2中_array地址和d2中_array地址相同,发生浅拷贝。赋值运算符重载要注意几点

1.赋值运算符重载必须要为类的成员函数,因为如果我们不在成员函数中重载,编译器调用的时候就不知道到底是调用你在全局中写的那个函数,还是在类中编译器为你默认生成那个重载函数

2.要注意还要支持连续赋值和自己给自己赋值的情况:

7.重载前置++和后置++(后置++要加上一个参数,因为这是要与前置++形成重载让编译器识别)

我们运行检查一下是否正确

同理我们可以写出前置--和后置--

8.取地址(&)运算符重载

7.const修饰类的成员函数

将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

当然也有例外就是被mutable修饰的成员变量仍然可以在const函数中被修改

1. const对象可以调用非const成员函数吗?答案:不可以,因为const对象只是一个可读对象,调用非const成员函数有可能在内部对其进行修改。2. 非const对象可以调用const成员函数吗?答案:可以调用,因为非const对象本事是一个可读可写的对象,可以对他修改或者不修改。3. const成员函数内可以调用其它的非const成员函数吗?答案:不可以因为在调用其他非const成员函数时有可能将const成员函数中原本不可以修改的成员变量修改。4. 非const成员函数内可以调用其它的const成员函数吗?答案:可以因为非const成员函数可以对函数内部的对象可读可写,而const成员变量内部只可以对对象可读,所以没有不安全的操作。最后在说一个C++中小技巧:

看到这里如果觉得有用不如点个赞吧!!! 

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/779367.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号