C++关键字集合
1.Static
Static 最大的作用是限定作用域。
1.面向对象的
静态成员变量
- 静态成员变量是该类的所有对象所共有的。对于普通成员变量,每个类对象都有自己的一份拷贝。整个运行过程中,静态成员变量一共就一份,只分配一次内存,由该类的所有对象共享访问。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;
- 因为静态数据成员在全局数据区分配内存,由本类的所有对象共享,所以,它不属于特定的类对象,不占用对象的内存,而是在所有对象之外开辟内存,在没有产生类对象时其作用域就可见。因此,在没有类的实例存在时,静态成员变量就已经存在,我们就可以操作它。且不能在定义对象时对变量进行初始化,不能用构造函数进行初始化, 需要在类外进行初始化。int Myclass::Sum=0;是定义并初始化静态成员变量
- static 成员变量和普通 static 变量一样,编译时在静态数据区分配内存,到程序结束时才释放。这就意味着,static 成员变量不随对象的创建而分配内存,也不随对象的销毁而释放内存。而普通成员变量在对象创建时分配内存,在对象销毁时释放内存。
- 静态数据成员初始化与一般数据成员初始化不同。初始化时可以不加 static,但必须要有数据类型。被 private、protected、public 修饰的 static 成员变量都可以用这种方式初始化。静态数据成员初始化的格式为:<数据类型><类名>::<静态数据成员名>=<值>
- 类的静态成员变量访问形式1:<类对象名>.<静态数据成员名>
- 类的静态成员变量访问形式2:<类类型名>::<静态数据成员名>,也即,静态成员不需要通过对象就能访问。
- 静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
- 如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;
- sizeof 运算符不会计算 静态成员变量。
同全局变量相比,使用静态数据成员有两个优势:
- 静态成员变量没有进入程序的全局命名空间,因此不存在与程序中其它全局命名冲突的可能。
- 可以实现信息隐藏。静态成员变量可以是private成员,而全局变量不能。
静态成员函数
静态成员函数为类服务而不是为某一个类的具体对象服务。静态成员函数与静态成员变量一样,都是类的内部实现,属于类定义的一部分。普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。
与普通函数相比,静态成员函数属于类本身,而不作用于对象,因此它不具有this指针。正因为它没有指向某一个对象,所以它无法访问属于类对象的非静态成员变量和非静态成员函数,它只能调用其余的静态成员函数和静态成员变量。从另一个角度来看,由于静态成员函数和静态成员变量在类实例化之前就已经存在可以访问,而此时非静态成员还是不存在的,因此静态成员不能访问非静态成员。
2.面向过程的
静态全局变量
静态全局变量有以下特点:
- 该变量在全局数据区分配内存;
- 未经初始化的静态全局变量会被程序自动初始化为0(自动变量的自动初始化值是随机的);
- 静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的;
- 静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。对于一个完整的程序,在内存中的分布情况如下:【代码区】【全局数据区】【堆区】【栈区】,一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区,静态数据(即使是函数内部的静态局部变量)存放在全局数据区。自动变量一般会随着函数的退出而释放空间,而全局数据区的数据并不会因为函数的退出而释放空间。
在一个文件中,静态全局变量和全局变量功能相同;而在两个文件中,要使用同一个变量,则只能使用全局变量而不能使用静态全局变量。
静态局部变量
静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;函数对其依旧可控
静态函数
静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。其它文件中可以定义相同名字的函数,不会发生冲突;
2. const
修饰普通变量
例如:
const int NUM = 10; //与int const NUM等价
NUM = 9; //编译错误,不可再次修改
由于使用了const修饰NUM,使得NUM为只读,因此尝试对NUM再次赋值的操作是非法的,
修饰数组
例如使用const关键字修饰数组,使其元素不允许被改变:
const int arr[] = {0,0,2,3,4}; //与int const arr[]等价
arr[2] = 1; //编译错误
试图修改arr的内容的操作是非法的,编译器将会报错:
error: assignment of read-only location ‘arr[2]’
修饰指针
修饰指针的情况比较多,主要有以下几种情况:
1.常量指针,是一个指向 const 的指针,对于指向的内容是只读属性。(就是修饰 *p)
const int * p;
int const * p;
2.指针常量。指针本身就是常量。(就是修饰 p 这个地址)
一旦指针使用了某个地址进行初始化,那么它就不能指向除此地址之外的任何其他东西。:
int value = 22;
int *const ptr = &value;
3.指针不可改变指向,指向的内容也不可变
int a = 9;
int b = 10;
const int * const p = &a;//p既是一个const指针,同时也指向了int类型的const值
*p = 11; //编译错误,指向的对象是只读的,不可通过p进行改变
p = &b; //编译错误,p是一个const指针,只读,不可变
修饰函数形参
如果确定传入的指针参数仅用于访问数据,那么应该将其声明为一个指向const限定类型的指针,避免函数对这部分数据进行意外地修改。
修饰函数返回值
就是将返回值,附带上 const 属性。和const修饰普通变量以及指针的含义基本相同。如果返回值为某个对象为const 或某个对象的引用为const,则返回值具有const属性,返回实例只能访问该对象类中的公有(保护)数据成员和const成员函数
类中的const成员函数(常量成员函数)
任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员函数,编译器将指出错误,这无疑会提高程序的健壮性。
<类型说明符> <函数名> (<参数表>) const;
3. volatile
mutalbe 的中文意思是“动荡不定的”, 用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。因此,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,每次都会重新从地址中读取,从而可以提供对特殊地址的稳定访问。
volatile int i = 10;
多线程下的volatile
有些变量是用 volatile 关键字声明的。当两个线程都要用到某一个变量且该变量的值会被改变时,应该用 volatile 声明,该关键字的作用是防止优化编译器把变量从内存装入 CPU 寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile 的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值。
4. mutable
mutalbe 的中文意思是“可变的”,是constant(即C++中的const)的反义词。在C++中,mutable也是为了突破const的限制而设置的,被mutable修饰的变量将永远处于可变的状态。
mutable的作用有两点:
(1)保持常量对象中大部分数据成员仍然是“只读”的情况下,实现对个别数据成员的修改;
(2)使类的const函数可以修改对象的mutable数据成员。 这也是该关键字最主要的作用
使用mutable的注意事项:
(1)mutable只能作用于类的非静态和非常量数据成员。