Static
变量
局部变量
普通局部变量是再熟悉不过的变量了, 在任何一个函数内部定义的变量(不加static修饰符)都属于这个范畴。编译器一般不对普通局部变量进行初始化, 也就是说它的值在初始时是不确定的, 除非对其显式赋值。
- 普通局部变量存储于进程栈空间, 使用完毕会立即释放。
静态局部变量使用static修饰符定义, 即使在声明时未赋初值, 编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区, 即使函数返回, 它的值也会保持不变。
- 变量在全局数据区分配内存空间;编译器自动对其初始化
其作用域为局部作用域, 当定义它的函数结束时, 其作用域随之结束
示例代码如下
|
运行结果如下
"/mnt/d/Computer/C++ learns/cmake-build-release/Cpp_learns" |
在fun()
中, 即便num++
下次运行num还是10
, 但对于fun_static()
, num++
会影响到下次运行的结果, 证明当局部变量加上static
关键字后, 在函数结束时, 它的值也保持不变, 并不会被释放
全局变量
全局变量定义在函数体外部, 在全局数据区分配存储空间, 且编译器会自动对其初始化。
普通全局变量对整个工程可见, 其他文件可以使用extern外部声明后直接使用。也就是说其他文件不能再定义一个与其相同名字的变量了(否则编译器会认为它们是同一个变量)。
静态全局变量仅对当前文件可见, 其他文件不可访问, 其他文件可以定义与其同名的变量, 两者互不影响。
- 在定义不需要与其他文件共享的全局变量时, 加上static关键字能够有效地降低程序模块之间的耦合, 避免不同文件同名变量的冲突, 且不会误使用。
函数
函数的使用方式与全局变量类似, 在函数的返回类型前加上static, 就是静态函数。其特性如下:
静态函数只能在声明它的文件中可见, 其他文件不能引用该函数
不同的文件可以使用相同名字的静态函数, 互不影响
非静态函数可以在另一个文件中直接引用, 甚至不必使用extern声明
下面两个文件的例子说明不使用static声明的函数文件互相影响
/* file.cpp */ |
运行结果
/tmp/cc9s5Fnk.o: In function `fun1()': |
修改文件
/* file.cpp */ |
运行结果
➜ Desktop g++ file.cpp file2.cpp |
类
静态数据成员
在类内数据成员的声明前加上关键字static, 该数据成员就是类内的静态数据成员。先举一个静态数据成员的例子。
|
可以看出, 静态数据成员有以下特点:
- 对于非静态数据成员, 每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个, 静态数据成员在程序中也只有一份拷贝, 由该类型的所有对象共享访问。也就是说, 静态数据成员是该类的所有对象所共有的。对该类的多个对象来说, 静态数据成员只分配一次内存, 供所有对象共用。所以, 静态数据成员的值对每个对象都是一样的, 它的值可以更新;
- 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间, 所以不能在类声明中定义。在上述代码中, 语句
int Myclass::Sum=0;
是定义静态数据成员; - 静态数据成员和普通数据成员一样遵从
public , protected , private
访问规则; - 因为静态数据成员在全局数据区分配内存, 属于本类的所有对象共享, 所以, 它不属于特定的类对象, 在没有产生类对象时其作用域就可见, 即在没有产生类的实例时, 我们就可以操作它;
- 静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:
<数据类型><类名>::<静态数据成员名>=<值> - 类的静态数据成员有两种访问形式:
<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
如果静态数据成员的访问权限允许的话(即public的成员), 可在程序中, 按上述格式来引用静态数据成员 ; - 静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类, 每个实例的利息都是相同的。所以, 应该把利息设为存款类的静态数据成员。这有两个好处, 第一, 不管定义多少个存款类对象, 利息数据成员都共享分配在全局数据区的内存, 所以节省存储空间。第二, 一旦利息需要改变时, 只要改变一次, 则所有存款类对象的利息全改变过来了;
- 同全局变量相比, 使用静态数据成员有两个优势:
- 静态数据成员没有进入程序的全局名字空间, 因此不存在与程序中其它全局名字冲突的可能性;
- 可以实现信息隐藏。静态数据成员可以是private成员, 而全局变量不能;
静态成员函数
与静态数据成员一样, 我们也可以创建一个静态成员函数, 它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样, 都是类的内部实现, 属于类定义的一部分。普通的成员函数一般都隐含了一个this指针, this指针指向类的对象本身, 因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下, this是缺省的。如函数fn()
实际上是this->fn()
。但是与普通函数相比, 静态成员函数由于不是与任何的对象相联系, 因此它不具有this指针。从这个意义上讲, 它无法访问属于类对象的非静态数据成员, 也无法访问非静态成员函数, 它只能调用其余的静态成员函数。下面举个静态成员函数的例子。
|
运行效果
"/mnt/d/Computer/C++ learns/cmake-build-release/Cpp_learns" |
关于静态成员函数, 可以总结为以下几点:
出现在类体外的函数定义不能指定关键字static;
静态成员之间可以相互访问, 包括静态成员函数访问静态数据成员和访问静态成员函数;
非静态成员函数可以任意地访问静态成员函数和静态数据成员;
静态成员函数不能访问非静态成员函数和非静态数据成员;
由于没有this指针的额外开销, 因此静态成员函数与类的全局函数相比速度上会有少许的增长;
调用静态成员函数, 可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数, 也可以直接使用如下格式:
<类名>::<静态成员函数名>(<参数表>)
调用类的静态成员函数