static
- 作用域隐藏。当一个工程有多个文件的时候,用static修饰的函数或变量只能够在本文件中可见,文件外不可见。
- 全局生命周期。用static修饰的变量或函数生命周期是全局的。被static修饰的变量存储在静态数据区。
- static修饰的变量默认初始化为0。(初始化会存在data段,未初始化是在bss段)
- 在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的静态成员变量。
1、修饰普通变量:修改变量的存储区域和生命周期,使变量存储在静态区,在main函数运行前就分配了空间,如果有初始值就用初始值初始化它,如果没有初始值系统用默认值初始化它。
2、修饰普通函数,表明函数的作用范围,仅在定义该函数的文件内才能使用。在多人开发项目时,为了防止与他人命令函数重名,可以将函数定位为static。
3、修饰成员变量,属于整个类所拥有,也就是说当某个类的实例修改了该静态成员变量,其修改值为该类的其它所有实例所见。静态成员变量是静态存储的,所以必须对它进行初始化
4、修饰成员函数,属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。
static成员函数不能为virtual:
1.static成员不属于任何类对象或类实例,所以即使给此函数加上virutal也是没有任何意义的。
2.静态与非静态成员函数之间有一个主要的区别。那就是静态成员函数没有this指针。
虚函数依靠vptr和vtable来处理。vptr是一个指针,在类的构造函数中创建生成,并且只能用this指针来访问它,因为它是类的一个成员,并且vptr指向保存虚函数地址的vtable.
对于静态成员函数,它没有this指针,所以无法访问vptr. 这就是为何static函数不能为virtual.
虚函数的调用关系:this -> vptr -> vtable ->virtual function
通过下面例子可以确定,当类增加了一个虚函数后,类的大小会增大4字节(指针的大小).
1 | class Test |
static成员函数不能为const函数
C++编译器在实现const的成员函数的时候为了确保该函数不能修改类的中参数的值,会在函数中添加一个隐式的参数const this*。但当一个成员为static的时候,该函数是没有this指针的。也就是说此时const的用法和static是冲突的。
volatile的道理也是如此。
const
1、修饰变量,说明该变量不可以被改变;
2、修饰指针,有以下三种情况:
- A: const 修饰指针指向的内容,则内容为不可变量。
- B: const 修饰指针,则指针为不可变量。
- C: const 修饰指针和指针指向的内容,则指针和指针指向的内容都为不可变量。
对于 A:1
const int *p = 8;
则指针指向的内容 8 不可改变。简称左定值,因为 const 位于 * 号的左边。
对于B:1
2
3
4
5int a = 8;
int* const p = &a;
*p = 9; // 正确
int b = 7;
p = &b; // 错误
对于 const 指针 p 其指向的内存地址不能够被改变,但其内容可以改变。简称,右定向。因为 const 位于 * 号的右边。
对于C:则是 A 和 B的合并1
2int a = 8;
const int * const p = &a;
这时,const p 的指向的内容和指向的内存地址都已固定,不可改变。
对于 A,B,C 三种情况,根据 const 位于 号的位置不同,总结三句话便于记忆的话:*”左定值,右定向,const修饰不变量”。
3、常量引用,经常用于形参类型,即避免了拷贝,又避免了函数对值的修改;
4、修饰成员函数,说明该成员函数内不能修改成员变量,如果要修改可以使用mutable关键字修饰这个成员变量。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using namespace std;
class Test
{
public:
Test(int _m,int _t):_cm(_m),_ct(_t){}
void Kf()const
{
++_cm; // 错误
++_ct; // 正确
}
private:
int _cm;
mutable int _ct;
};
int main(void)
{
Test t(8,7);
return 0;
}
const和define的区别
类型和安全检查不同
宏定义是字符替换,没有数据类型的区别,同时这种替换没有类型安全检查,可能产生边际效应等错误;
const常量是常量的声明,有类型区别,需要在编译阶段进行类型检查
编译器处理阶段不同
宏定义是一个”编译时”概念,在预处理阶段展开;
const常量是一个”运行时”概念,在程序运行使用,类似于一个只读行数据
存储方式不同
宏定义是直接替换,不会分配内存,存储于程序的代码段中;我理解的是给出的是立即数,有多少次使用就进行多少次替换,在内存中会有多个拷贝,消耗内存大;
const常量需要进行内存分配,存储于程序的数据段中,编译期最初将其保存在符号表中,第一次使用时为其分配内存,在程序结束时释放;const局部变量存储在栈中,代码块结束时释放
定义域不同1
2
3
4
5
6
7
8
9
10void f1 ()
{
const int n 12;
}
void f2 ()
{
cout<<N <<endl; //正确,N已经定义过,不受定义域限制
cout<<n <<endl; //错误,n定义域只在f1函数中
}
定义后能否取消
宏定义可以通过#undef来使之前的宏定义失效
const常量定义后将在定义域内永久有效1
2
3
4
5
6
7
8void f1()
{
const int n = 12;
}
是否可以做函数参数
宏定义不能作为参数传递给函数
const常量可以在函数的参数列表中出现
static和const联合使用
static与const作用:声明一个只读的静态变量
static const,既是只读的,又是只在当前模块中可见的