0.前言
static与c++的内存分布有很大关系,分析static关键字之前最好先了解一下c++内存分布(可以分为五个部分):
1、栈区(stack): 是那些编译器在需要时分配,在不需要时自动清除的存储区。存放局部变量、函数参数。
2、堆区(heap):一般由程序员分配释放,如new、delete。 若程序员不释放,程序结束时可能由OS回收 。
3、全局数据区(静态区):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后由系统释放。
4、只读常量区:存放常量,不允许修改(通过非正当手段也可以修改)。
5、代码区:存放代码(如函数),不允许修改(类似常量存储区),但可以执行(不同于常量存储区)。
在c++中,static的应用可以分为五种类型,以下分别介绍:
1.静态全局变量
在全局变量前加上 static 关键字,即为静态全局变量;
静态全局变量在程序的全局数据区分配内存,直到程序结束才销毁;
static int i = 0; //静态全局变量,初值为0
void fun() //fun每被调用一次,全局变量i的值就增加1
{
i += 1;
}
void main(){
int k = 0;
while(k < 100){
fun();
k++;
}
}
静态全局变量与普通全局变量的区别:
…静态全局变量是 internal 属性.,在该文件内可见,从变量定义处开始直到文件结束,而在其他文件中不可见(include关系除外)。
…普通全局变量在同一程序的其他文件中可见,默认是 external 属性。
举例说明(两个文件):
//a1.cpp
static int x = 10; //静态全局变量
int y = 10; //普通全局变量
//a2.cpp
#include<iostream>
extern int y; //使用extern让a2.cpp取寻找其它文件中定义的普通全局变量y
extern int x; //报错,静态全局变量会进行 文件隔离
int main(){
cout<<y; //10
y++;
cout<<y; //11
//cout<<x; //报错
return 0;
}
可见,通过extern可以使用其它文件的普通全局变量,而静态全局变量却不能跨文件使用(#include除外).
我们可以说,静态全局变量具有文件隔离的作用,我们定义静态全局变量的时候不用担心其它文件是否定义过同名的全局变量,这一点十分有利。
2.静态局部变量
静态局部变量一般被声明在一个会被多次调用的函数体内。
静态局部变量特点:
1)该变量在全局数据区分配内存; (但作用范围与普通局部变量相同)
2)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后函数调用不再进行初始化;
3)静态局部变量每次的值保持到下一次调用(退出函数,空间不回收)。
void fun()
{
static x=0; //作用范围仅在fun()函数体内
//仅第一次执行时才会初始化,之后不在初始化。
cout<<x<<endl;
x++;
}
void main(){
fun(); //输出0 此时静态局部变量x被初始化
fun(); //输出1
fun(); //输出2
}
3.静态函数
在函数的返回类型前加上 static 关键字,函数即被定义为静态函数。
静态函数与静态全局变量类似,具有文件隔离的作用。
static void fun (); // 声明静态函数
void main()
{
fun();
}
void fun () // 定义静态函数
{
cout<<"static function"<<endl;
}
4.静态数据成员
上述1、2、3是c和c++都具有的功能。
而后面4和5中静态数据成员与静态成员函数,仅是c++中的概念。
静态数据成员是每个类有一份,普通数据成员是每个 对象(实例)有一份,因此静态数据成员也叫做类变量,而普通数据成员也叫做实例变量。
换句话说,静态数据成员是该类的所有对象所共有的。
静态数据成员的初始化需要在类外。
格式为: <数据类型><类名>::<静态数据成员名>=<值>
静态数据成员有两种访问形式: <类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
下面是一段通过测试的代码,可以说明上述特点:
#include<iostream>
using namespace std;
class Myclass
{
public:
Myclass(int a) {
m_a = a;
Sum += m_a;
}
int GetSum() { return Sum; }//普通成员函数是可以调用静态数据成员的
static int Sum;// 声明静态数据成员,属于类的变量,所有实例共享唯一Sum
private:
int m_a;
};
int Myclass::Sum = 0;// 定义并初始化静态数据成员
void main() {
Myclass instance1(5);//实例1
cout << instance1.GetSum() << endl; //5
Myclass instance2(3);//实例2
cout << instance2.GetSum() << endl; //8
cout << instance2.Sum << endl; //8
cout << Myclass::Sum << endl; //8
cout << ++Myclass::Sum << endl; //9
system("pause");
}
}
5.静态成员函数
但是与普通成员函数相比,1)静态成员函数由于不是与任何的对象相联系,因此它不具有 this 指针。2)静态成员函数只能访问静态数据成员和静态成员函数,而普通成员函数可以访问静态成员函数和静态数据成员。
#include<iostream>
using namespace std;
class Myclass
{
public:
Myclass(int a) {
m_a = a;
Sum += m_a;
}
static int GetSum() { //静态成员函数,可以直接类内定义
//cout << m_a << endl; // 错误,不能访问非静态成员
return Sum;
}
static int Sum; // 声明静态数据成员
private:
int m_a;
};
int Myclass::Sum = 0;// 定义并初始化静态数据成员
void main() {
Myclass instance1(5);
cout << instance1.GetSum() << endl; //5 instance1.GetSum()访问形式
Myclass instance2(3);
cout << Myclass::GetSum() << endl; //8 Myclass::GetSum() 访问形式
cout << instance2.Sum << endl; //8
cout << Myclass::Sum << endl; //8
cout << ++Myclass::Sum << endl; //9
system("pause");
}