1. const
作为一个程序员,我们看到关键字const时,首先想到的应该是:只读。因为,它要求其所修饰的对象为常量,不可对其修改和二次赋值操作(不能作为左值出现)。看几个例子:
const int a;
//同上面的代码行是等价的,都表示一个常整形数。
int const a;
/* const具有"左结合"性,即const修饰*,那么,不难理解,该句表示一个指向整数的常指针,
a指向的整数可以修改,但指针a不能修改。
*/
int *const a;
/* 同理,下面的这两行,根据"左结合"性,const修饰的是(*a),也即是一个整数,
所以,这两句表示指针指向一个常整数。
*/
const int *a;
int const *a;
//根据"左结合"性质,第一个const修饰(*),第二个const修饰(a),因此,这句话表示一个指向常整数的常指针。
int const *a const;
合理的使用const关键字,不仅能够让编译器很好的保护相应的数据,还能够直观的向代码的阅读者传递有用信息。
2. static
a) static在面向过程编程中的使用场景包括三种:
1) 修饰函数体内的变量(局部)
2) 修饰函数体外的变量(全局)
3) 修饰函数
第一种情况,static延长了局部变量的生命周期,static的局部变量,并不会随着函数的执行结束而被销毁,当它所在 的函数被第再次执行时,该静态局部变量会保留上次执行结束时的值。如:
1 #include <stdio.h>
2
3 void test()
4 {
5 static int j = 1;
6 printf("%d\n", j);
7 j++;
8 }
9 int main()
10 {
11 test();
12 test();
13
14 return 0;
15 }
输出的结果是:
1
2
对于后面的两种情况,static是对它修饰的对象进行了作用域限定,static修饰的函数以及函数外的变量,都是只能在当前的源文件中被访问,其它的文件不能直接访问。当多个模块中有重名的对象出现时,我们不妨尝试用static进行修饰。
b)在面向对象编程中,static可以被用来修饰类内数据成员和成员函数。
1) 修饰数据成员
*)被static修饰的数据成员实际上相当于类域中的全局变量。因此,对于类的每个对象来说,它是共有的。它在整个程序中只有一份拷贝,只在定义时分配一次内存,供该类所有的对象使用,其值可以通过每个对象来更新。由于静态数据成员存储在全局数据区,因此,在定义时就要分配内存,这也就导致静态数据成员不能在类声明中定义。
*)静态数据成员的初始化举例: int ClassTest::num = 0;
*)静态数据成员的访问举例: ClassTest ClassInstance; ClassInstance.num 或者 ClassTest::num
#include <iostream>
class CTest
{
public:
CTest() {};
~CTest() {};
public:
static int num; //声明
};
int CTest::num = 10; //定义
int main(void)
{
CTest obj;
std::cout << obj.num << std::endl; //访问
std::cout << CTest::num << std::endl; //访问
return 0;
}
2)修饰成员函数
*)同静态数据成员一样,静态成员函数也是属于类,而不属于任何一个类的实体对象,因此,静态成员函数不含有this指针。同时,它也不能访问类中其它的非静态数据成员和函数。(非静态成员函数可以访问静态数据数据成员和静态成员函数)
*)静态成员函数的访问方式: 既可以通过访问操作符(.)或者(->)来访问,也可以通过 <类名> :: <函数名> 的方式访问。
3. volatile
volatile的作用是告知编译器,它修饰的变量随时都可能被改变,因此,编译后的程序每次在使用该变量的值时,都会从变量的地址中读取数据,而不是从寄存器中获取。