C++中的各种关键字
const的作用
- const作用,总结起来就是我希望被const修饰的东西不允许更改,也就是是只读
- const修饰变量
- const修饰变量的意思就是不允许修改这个变量,也就是定义一个常量,这个常量在程序运行中不允许修改,所以const修饰变量时,必须进行初始化。
- const修饰变量也分为const修饰成员变量和const修饰全局变量,虽然他们在程序中都作为常量使用,但是就像刚刚所说的,本质上他们其实都是变量,所以const修饰的成员变量内存仍然是放在栈上的,而const全局变量则放在常量只读区,这意味着在栈上的const成员变量还是有特殊办法改变的,而全局const变量就没办法改变了,虽然这其实没有意义,只不过是我学习过程中的一个有意思的点而已。
- const修饰引用
- 引用就是对一个对象的别称,当const修饰一个引用时候,和修饰变量有所不同的是,修饰引用时,并不意味着这个对象是常量,只是代表我们不能通过这个别称修改这个对象,也就是这个别称是只读的。
- 比较经典的用法就是我们在使用函数传递参数时,基本上能选择传递引用就传递引用,因为效率更高嘛,但是如果我不希望在函数中不小心更改了这个参数,加上const限定就保证在函数中不能修改这个参数了,另外一个例子就是,我们定义了一个int a,和一个对它的常量引用b,我们修改b会报错,因为他是常量引用,而我们修改a,则b也会跟着修改,就非常好的说明了,const引用是只读的意思。
- 此外还有一点就是常量引用能引用左值和右值,,但是普通引用也就是左值引用只能引用左值
- const修饰指针
- const修饰指针具体要分成常量指针和指针常量,具体就看const的位置,比如定义一个常量指针,const int _ a,const放在最前面,实际上const作用于后面的_a,也就是 _a只读不能更改, _a代表的就是a这个指针指向的内容,也就是这个内容的值是不能更改的,但是a本身是可以改的,也就是指针指向可以更改。
- 而如果是int* const a 的话,const具体修饰的就是a,意思就是a本身不能更改,也就是a的指向不能更改,但是a指向的内容的值可以更改。
- const修饰函数
- const修饰函数的本质就是const修饰this指针,也就是我们不能改动这个对象的成员,当我们对一个函数加上const时,就意味着我们保证在这个函数中不会修改成员。而一个类的const对象,只能调用它的const函数,因为const对象不允许修改成员,只有const函数保证不修改成员,而一个类的普通对象是可以调用const与非const函数的。
- 此外一个函数加不加const他们的函数签名是不同的,也就是能形成重载的,而如果两个函数同时存在,则const对象调用const版本,而非const对象调用非const版本
static的作用
- static可以对变量和函数进行修饰分为三种情况
- 在用于文件域中时,也就是我们在定义全局变量时,加上static意味着这个变量限定在了这个文件中使用,其他文件调用不到。
- 在用于函数域中时,比如我们在函数体中定义并初始化了一个静态变量,同时对这个变量进行其他操作。这个静态变量是全局的,存放在静态区中,但是只在这个函数中可见,最重要的是这个变量只进行一次初始化,也就是说当我们重复调用这个函数的时候,初始化的那一句只有在最开始的时候执行一次分配内存并初始化,此后的函数不在调用,只会执行其他语句。
- 在用于类中时,即静态成员变量和静态成员函数
- 静态成员变量意味着这个变量不在属于类对象而属于整个类,也就是这个变量会存放在静态全局区,而不是每个类对象的空间上,而所有类调用的都是同一份这个静态变量,也就不允许在类中初始化,必须在类外初始化,避免每次创建类对象的时候重复定义这个静态变量。
- 而当static修饰类中的成员函数时,就代表着这个函数只能操作同样是static的成员变量,而不能操作其他变量。具体解释的话就是静态成员属于整个类而不属于单独某个类对象,除了静态变量以外,其他变量都是属于各自类对象的,函数无法使用具体对象的成员,只能使用属于整个类的成员,底层的实现手段就是函数调用时不传入this指针,在调用普通类成员函数时,会传入this指针告诉函数是哪个对象在使用这个函数,操作成员变量时操作的是谁的成员变量,static函数就不传入this指针,也就是它不知道是谁在调用它,因此它就没办法使用具体谁的成员对象
extern的作用
- extern修饰变量名或者函数名声明意思为外部链接,即去其他文件中寻找该变量或者函数的定义,当然如果定义变量前面加了static就会失败,因为static全局变量以为着只允许它那个文件中使用
- extern"C" 意思是按照C语言的编译器风格翻译,在函数定义中,C在函数名上会加上参数,因为C要是实现重载,而C不用,所以当C++要去调用一个C风格的函数时就会报错,就要用到extern"C"。
explicit的作用
- 当类的构造函数只有一个参数的时候,编译器会把单独这个类型的数隐式转换成一个类对象,比如我们的隐式构造实际上就是运用了这个隐式转换
- 而当我们在这个构造函数前面加上explicit时,就限定这个构造函数必须显示构造,避免了某些隐式转换带来的问题。
constexpr的作用
- 就是告诉编译器后面这个是一个常量表达式,要求它要在编译期就计算出来,而不是在运行的时候,放在函数前面就代表着这个函数本质上就是一个常量表达式,通常是只能有一个return语句,但是这个好像在最新的C++没有那么严格我没有具体去了解。
- 通过这个关键字可以在编译期让编译器去计算很多东西,就可以节省程序运行时候的性能,没记错的话我在stl的源码中看到过挺多这个关键字,只不过我个人使用的比较少,唯一用过的可能还是在leetcode上耍的小聪明,有一些题目在运行的时候计算要花费很多时间,但是如果有的函数或者表达式加上constexpr,就能让编译器在编译阶段计算,就能让最后的运行时间节省很多。
volatile的作用?
- 跟编译器优化有关,告诉编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的备份。
- 比如我们定义了一个cosnt常量,C++会进行优化把这个常量放进符号表中,当用到这个常量时从符号表中查询,而没有直接去这个常量的地址中查询,所以当我们用一些特殊手段修改了这个常量时,我们会发现,使用中它还是原来的值没有修改,而如果我们使用volatile修饰这个变量,编译器就会从内存中真正取出这个常量,就可以看到它改变了,
mutable的作用?
- 保持常量对象中大部分数据成员仍然是“只读”的情况下,实现对个别数据成员的修改;
- 使类的const函数可以修改对象的mutable数据成员。
auto和deltype的作用和区别?
- auto用于实现类型的自动推导,让编译器来操心变量的类型,但本质上auto并非一种类型的声明,而是一个类型声明时的占位符,编译器会在编译时期将auto替换成实际类型。
- 但是auto也有一些限制比如不能推导数组,不能用于函数传参,但是deltype可以解决这些问题。