【C++】C++中的关键字:const、mutable、auto、typedef、using、new、delete、explicit、this、多文件放代码

七、C++中的关键字:const、mutable、auto、typedef、using、new、delete、explicit、this、多文件放代码

本部分打算是尽量多的罗列出C++中的关键字和一些花式操作。先总结一下我们之前讲过的:
private、public、protect: 参考【C++】类、静态、枚举、重载、多态、继承、重写、虚函数_c++ 静态枚举-CSDN博客 中的第5小标题,可见性。
static: 参考上面博文中的第7个小标题
virtual、override:参考上面博文中的第13、14小标题
inline:参考 【C++】编译原理_c++编译原理-CSDN博客 中的最后部分。

1、const关键字

const是一个限定修饰符,表示承诺某个对象不能改变,是强制开发人员写代码时的一个规则,也就是语法上的一个规则。所以它在生成二进制代码方面是什么也没做的。只是在源代码中一旦你用const修饰了,你就得遵守,否则编译阶段就报错。也所以,const只是编译阶段的一个承诺而已,程序执行时也可能就不信守这个承诺了。所以const有时也称伪关键字。

(1)const修饰常量
在讲常量部分,有一个叫常变量的,就是就是用const限定一个常量,就变成常变量了。而且还展示了一个如何绕过承诺,修改一个const对象的例子,可以参考:【C++】深度理解C++数据类型:常量、变量、数组、字符串、指针、函数_c++ 字符串常量-CSDN博客 中的第一个小标题。

(2)const修饰指针

这部分也非常好理解,不理解的可以翻看指针部分。

(3)const在类中或者在方法中


上图的BCDE和FG都是多态。

小结:const用在类的方法中,一般都是这个方法声明不改变类的其他东西,就是读读,不修改的。这样做的目的就是让类外的函数更加方便快捷的调用这个类方法。如果类外的函数使用常量指针或者常量引用调用这个类方法,就不用拷贝参数了,效率就大大提升了。

(4)const修饰类实例
上面的例子理解了,这里就非常好理解了:

2、mutable关键字
mutable是字面意思是可改变的,immutable是不可改变的、无法改变的。
mutable有两种不同的用法:一种是和上面的const进行搭配使用;另一种是用在lambda表达式中。

(1)mutable和const搭配
前面讲const出现在类方法中时,表示这个类方法不能改变类中其他变量。但是如果这个类方法必须得改变类中的某些变量,而且它还想是个const方法时,就得用mutable关键字来修饰那个被改变得变量。numtable就相当于是const的逆或返。下面用两个小例子说明:

(2)mutable用在lambda表达式中

mutable用在lambda表达式中不是特别常见。尽量少用吧。

3、auto关键字

在C++中,所有变量在创建、初始化的时候,都是要有类型的,尤其是一些各种基本类型嵌套组合的对象,比如函数的返回类型、指针的指针、数组指针、指针数组等等,这些多重嵌套组合的类型是很多初学者对C++知难而退的最主要原因。

auto是让C++自动推导出数据类型的一个关键字,用法也非常简单,上图的lambda示例其实也是auto的示例。下面我再多举几个用法例子:

可见auto的用法真的很简单,所以单独讲auto的用法是没啥可讲的。
但是,到此对一些被类型搞得晕头转向的同学来说,似乎眼前一亮,找到了救星。肯定有人会想,有了auto我岂不是以后都不用考虑对象类型了?我全部用auto来替代,我到处写auto不行吗?!所以,本小标题重点聊聊使用auto的优劣、以及啥情况需要使用auto?啥情况最好别用auto?

下面再举一个例子,来说明代码中使用auto的好处和弊端:

上面的例子举得不太好,x是局部变量,随着GetName调用完毕就消失了,所以大家看看就好,主要是说明auto有时还是好用的。

但是auto的弊端更多:
一是,读代码的人打眼一看,就被迷惑了,b到底是什么类型呢?然后用鼠标悬停上面才知道原来是个int*;或者得实地查看GetName函数,看它到底返回的是啥类型,如果GetName函数再在别的文件中,就让人非常心烦。所以大量使用auto会使代码可读性变得极差。
二是,当API出现改动时,使用auto会隐式地帮我们也改变了很多东西,这会导致未来运行时出现bug或者其他问题,我们就很难发现。
三是,当我们大量使用auto时,C++就变得和其他弱类型托管语言无二了,那C++的最无可替代的优势————性能,就无法体现了。C++这么晦涩但还一直经久不衰,就是因为底层的效率,你这样不如直接用其他语言更简单。此外,auto本身背后也是大量代码的包装,一个auto背后是要去各种检查,比如检查是不是指针,如果是还得判断指向的内存是否需要释放等等的判断。所以auto本身就代表着低效。

所以如果我们遇到的是上面的情况,我们要尽量避免使用auto。那什么时候使用auto?下面展示一个使用场景:

再展示一个更加繁琐的类型:

这个例子就是典型的类型嵌套,而且非常复杂,此时上例中黄色框住的部分就可以用auto代替:

所以,当我们的类型非常复杂,非常长的时候,使用auto代码要简洁得多,此时使用auto就非常合适。A

4、typedef、using关键字
文接A处:
但是当我们面对这种情况,解决方法也不仅限于使用auto,还可以使用typedef,也可以使用using:

还可以把using或者typedef写到类里面:

打印时也可以写成这样:

补充5:如何使用多个文件
文接上例,上例还可以放到多个文件中:

再整齐一点:

再简洁一点:

知识点错综复杂,所以真是想到哪里写到哪里。

6、new、delete
其实这两个关键字是一个大话题,也很深奥。它牵扯到内存分配、堆、栈、系统如何创建对象、性能、优化等概念。建议搭配 【C++】如何用C++创建对象,理解作用域、堆栈、内存分配-CSDN博客 一起理解。

(1)new的主要目的是在堆上分配内存
关于new和delete我们之前的代码中就出现过,当时我们只是说有名字的对象都是静态对象;没有名字的对象是动态对象,需要程序员使用new和delete来显式的创建和释放;动态对象存放在堆上:

(2)new和delete背后的逻辑
当我们用new在上创建对象时,系统就会在堆上分配内存、并调用构造函数。

当我们new 数据类型后,就意味着需要在内存堆上寻找一块连续的区域,这个区域要等于数据类型的长度,来存放我们new的对象。比如 new int;后,就表示C++语言标准库你要分配给我4个连续的内存空间。此时写入不写入数据就是另一回事了,当前需要的是先在一行内存中找到4个字节的连续空间块。此时有一个叫空闲列表的东西,它是维护那些空闲字节的地址的,所以要给它一些时间(当然也很快),它通过一些算法或者基于某些策略(比如基于作用域的指针、或者引用计数等)给我们找到最优的一块内存区。找到连续内存区域后,就会立即返回一个指向该地址的指针。然后才是该写入就写入、该读就读,反正有指针已经指向这块空间了。

所以,当我们new 数据类型时,就会返回一个该类型*的指针。这个指针的值就是我们在堆上创建的无名对象的首地址,而数据类型就是表示这个对象的大小或者说是长度。之所以要返回一个指针是因为我们new的堆对象是没有名字的,所以要返回一个指针,存储这个对象的首地址。也所以只要我们delete这个指针就表示delete了堆上的对象。也所以只要指针不丢,堆上的对象就一直存在。也所以我们copy这个对象时,不用真正copy这个对象的堆内存空间中的数据,我们只要copy指针中的地址就可以了。

一是,new和delete都是一个操作符。那既然是操作符,就表示应该有很多重载函数,所以你可以new int,也可以new int[]数组,还可以new class等等。

二是,我们调用new时,还会调用隐藏在里面的C函数malloc()、以及数据类型的构造函数。malloc()是分配内存的函数。

所以,如果我们自己写new函数,那我们得先用C中的malloc()函数分配内存并返回void指针,然后把woid指针强制转化成我们new的类型,然后再调用这个类型的构造函数。

三是,当我们new时创建的对象,这个对象是不会自动销毁的,也就是不会自动被放回空闲列表,所以这块空间就不能再被调用再分配了,直到我们手动调用delete,才会回收这块内存区域。
所以delete同理,先调用析构函数再调用C中的free()函数,free函数是用来释放malloc申请的内存的函数。

7、explicit关键字
explicit关键字主要用在C++的构造函数中,也就是构造函数自带有隐式转换
C++是允许编译器对代码执行一次隐式转换的。

可见隐式转换可以让我们的代码简单很多,但同时代码的可读性也差很多,所以建议慎用。
当你只是单纯的想显式的调用构造函数,而不想每次调用构造函数,还得默认编译器进行一次隐式转换,此时你可以用explicit。

8、this关键字
这个关键字我们在 【C++】C++中的花式操作:lambda表达式、类成员初始化列表、三元运算符、运算符及其重载。。。-CSDN博客 中的第13小标题运算符及其重载中使用过。这里专门针对这个关键字总结一下:
一是,this关键字仅限在类中使用。也就是你写类的时候才用到这个关键词,别的地方没有它。
二是,通过this关键字可以访问类方法。为什么?因为this是一个指向当前类实例的指针。你可以类比python中写类时的self,在python中写类方法时,都是要无脑加一个self的。因为类方法是和类实例绑定的,不然它就叫函数了干嘛叫方法呀。
三是,一般别没事在类中写个delete this;这个语句只有非常专业的人才用,如果你轻佻可能失去很多。。。其他也没什么,这个关键字不难,难点可能就是它的变换很多,你只要以不变应万变,那就不难了。

上图基本上就把this的用法就全部囊括了:
首先你要明天类实例是可以调用类中的public变量和类方法的。

A处:既然this是一个指向当前类实例的指针,那this肯定能赋值给E*指针p了。所以通过p自然能解引用到x,y了。同理,F处代码也顺理成章了。
C处:*this解引用就是实例本身,所以可以将它赋值给类引用ref。
B处:是类方法调用外部函数。此时外部函数的参数是const类引用。如果C处明白,那B处就应该可以明白。唯一的区别就是多了个const,是const类引用。只是承诺我不修改你,只是读一下。这里要强调的是,当在非const方法中this就是一个类指针,但是在const方法中(D和E处)this就变成了一个const类指针,如上图所示。

D处:是赋值给一个const指针。
E处:是赋值给一个const类引用。

待补充 。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值