首先了解一下内存的分布图:
代码区
全局数据区
堆区
栈区
代码区:存储代码
全局数据区:static 数据, 全局变量, const常量
堆区:由程序员自己new出来的动态数据, 需要手动释放。若忘记释放,会造成内存泄漏,则程序结束时会由操作系统回收。
栈区:函数内部变量,由IDE自动分配,结束时自动释放。
后续可以再仔细研究一下堆区和栈区的区别,这里先不讨论。
首先总结static全局变量和全局变量的区别:
-
两者的存储都是在全局数据区,存储方式相同
-
普通的全局变量,它作用在整个源程序,如果一个源程序有多个源文件,那这个全局变量在所有源文件中都有效
-
“”static”全局变量限制了它的作用域只在定义该变量的源文件内, 只能此文件的函数公用,其他的源文件不能使用该static全局变量,可以避免在其他源文件中使用而引起错误,其他文件还能命名相同名字的变量,不会发生命名冲突
再说一下static局部变量的用途与局部变量的区别:
先举个小栗子:
void fun()
{
static int i=1; // int i
count<<i<<endl;
i++;
}
void main()
{
fun();
fun();
}
正常情况下 函数内定义的局部变量,每当程序运行到这个语句时,会给这个变量分配内存到栈区,但当程序退出函数体时,系统就会自动回收栈内存,这个局部变量也就失效了。
而静态局部变量就能解决这个问题,它的内存保存在全局区,即使程序退出函数体,它也不会失效,它存储的值会 一直保存到直到下一次赋值
总结一下:
-
static局部变量在首次声明时被初始化,内存在全局数据区,之后再调用也不会初始化或重新分配内存。
-
static局部变量一般在声明时就赋值初始化,否则程序会默认初始为0。
-
static局部变量驻留在全局数据区,直到程序结束,但它的作用域还是局部作用域,当定义它的函数体结束时,作用域也就结束了。
static静态函数
static void func()//声明静态函数
与static全局变量相似,static函数只在当前源文件中可用,不能被其他文件所用,其他源文件也能定义相同名字函数,不会冲突
类中的static
举个栗子:
clase Myclass
{
private:
int a, b;
static int count;
public:
Myclass(int a,int b);
void Getcount();
}
int Myclass:: count =0;
Myclass::Myclass(int a,int b )
{
this->a = a;
this->b = b;
count += a+b;
}
void Myclass:Getcount()
{
cout<<“count =”<<cout<<endl;
}
int main()
{
Myclass A(1,2);
A.Getcount();
Myclass B(3,4);
B.Getcount();
A.Getcount();
B.Getcount();
return 0;
}
总结一下:static数据成员的特点:
- 通常,每次类分配一个对象。它的数据都会拷贝,但是static数据成员无论类的对象定义了多少个,它只拷贝了一份,由声明它的类的所有对象共用。也就是说不论是对象A,还是对象B 调用static数据成员变量,都是一样的。
- static数据成员不能定义在类中,需要在类外定义 int Myclass:: count =0;
- static数据成员也遵从private,public,protected访问规则
- 类的static成员有两种访问形式:(前提是public权限)
<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
static成员函数:
static成员函数不是为类的某一个对象服务,而是为类的所有所服务。
其实普通的成员函数都隐藏了一个this指针,它指向类对象本身,但通常情况下this是缺省的。而static成员函数并不属于某个具体的对象,所有它没有this指针。 也就是它无法访问类对象的普通成员函数,或普通数据成员,它只能调用static函数或数据成员。
举个栗子:
clase Myclass
{
private:
int a, b;
static int count; //静态数据成员
public:
Myclass(int a,int b);
static void Getcount(); //声明静态成员函数
}
int Myclass:: count =0;//初始化静态数据成员
Myclass::Myclass(int a,int b )
{
this->a = a;
this->b = b;
count += a+b;
}
void Myclass:Getcount()
{
// cout<<a<<endl ; //无法访问普通数据成员
cout<<“count =”<<cout<<endl;
}
int main()
{
Myclass A(1,2);
A.Getcount();
Myclass B(3,4);
B.Getcount();
A.Getcount();
Myclass::Getcount();
return 0;
}
总结一下static成员函数特点:
- “”static“”成员可以相互访问,比如static成员函数或static静态数据成员
- 普通成员函数可以访问静态成员函数和静态数据成员
- 静态成员函数无法访问普通的成员函数或数据成员
- 类外的函数定义不能使用static关键字
- 因为没有this指针,所以static成员函数会比类的全局函数速度快一点点
- 调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:
<类名>::<静态成员函数名>(<参数表>) 调用类的静态成员函数。