这篇文章对C++常见的一些关键字作一个总结,主要从关键字的基本概念、使用场景以及注意事项等方面叙述。
1. virtual
概念:virtual是定义虚函数的关键字。在使用virtual之前,C++对成员函数使用静态联编,而使用virtual,并且在调用时是通过指针或引用调用,C++则对成员函数进行动态联编。virtual具有继承性,即:只要基类定义了virtual,子类的该函数也就有virtual属性。
使用场景:
- 定义类函数,使其成为虚函数(友元函数、构造函数、static静态函数不能用virtual关键字修饰,普通成员函数和析构函数可以用virtual关键字修饰);
- 虚继承;
- 纯虚函数,包含纯虚函数的类为抽象类,不能实例化;
2. inline
inline是为了解决一些频繁调用的小函数大量消耗栈空间的问题而引入的。一般函数代码在10行之内,并且函数体内代码简单,不包含复杂的结构控制语句例如:while、switch,并且函数本身不是直接递归函数(自己调用自己)。
使用场景:
- 代码段比较小,一般小于10行;
- 函数被频繁调用;
注意事项:
- 递归调用的函数不应声明为inline函数;
- inline函数仅仅是一个对编译器的建议,能否内联要看编译器;
- inline定义的类的内联函数,函数代码被放入符号表中,在使用时直接进行替换,省去了参数压栈、栈帧开辟与回收、结果返回等,没有了调用的开销,效率高。比宏函数安全性高,会进行参数类型的检查,不会出现语义上的问题;
- 类中定义的函数,自动转换为内联函数;
- inline函数在运行时可以调试,而宏不可以;
缺点:
- inline函数的使用是空间换时间的方法。会导致代码量增加;
- inline函数无法随着函数库升级而升级;
- 在调用inline函数时,要保证内联函数的定义让编译器“看”到,也就是说内联函数的定义要在头文件中;
3. volatile
volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器位置的因素更改,比如:操作系统、硬件或者其它线程等。由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取RAM的优化。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
三大特性:
- 易变性:是在汇编层面反映出来的,就是两条语句,下一条语句不会直接使用上一条语句对应的volatile变量的寄存器内容,而是重新从内存中读取;
- 不可优化性:volatile所修饰的变量,编译器不会对其进行各种激进的优化;
- 顺序性:C/C++ 对volatile变量和非volatile变量之间的操作,是可能被编译器交换顺序的(交换后无变化,在有些地方这样处理就会出问题),对volatile变量间的操作,编译器不会交换顺序;
格式:类型 volatile 变量名;
举个栗子:
int main()
{
int volatile a = 10;
.
.
int c = a;
return 0;
}
在上述代码中,如果不加volatile,编译器可能会进行优化,在进行 c = a 的时候,编译器发现 a 为改变,就会将寄存器里存的a的值赋给 c,这对于非常容易改变变量的情况不适合,如果加了volatile,那么每次需要访问 a 的值都会从内存中读取(因为编译器认为此变量的值随时都可能改变)。
使用场景:
- 多任务环境下各任务间共享的标志应该加volatile;
- 中断服务程序中修改的供其它程序检测的变量需要加volatile;
- 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义;
(待更新 decltype、mutable)
Reference :