- 存在的就是合理的
- static的用法
代码区(低地址) |
全局数据区 |
堆区 |
栈区(高地址) |
example1.cpp
#include <iostream>
#include "example2.h"
using namespace std;
static int n; //定义静态全局变量
void fun();
int main()
{
n = 10;
cout<<n<<endl;
fun();
return 0;
}
example2.cpp
#include <iostream>
using namespace std;
extern int n;
void fun()
{
n++;
cout<<n<<endl;
}
代码分析:在example1.cpp中int n定义为static,因此在该文件中可见,所以编译时会报错,若删除关键字static,则编译通过。
2.静态局部变量
在局部变量之前加上关键字static,该变量就被定义成静态局部变量。通常在函数体内定义一个变量,每当程序运行到该语句时就会为该局部变量分配栈内存。当程序退出函数体时,系统会回收栈内存,局部变量也相应失效。
当我们需要在两次调用之间对变量的值进行保存,一般会想到用全局变量来实现,但这样的话变量就不属于函数本身,不再受函数控制,给程序维护带来不便。因此可以用静态局部变量来解决这个问题,静态局部变量保存在全局数据区,不保存在栈区,每次的值都保持到下次调用,直到下次赋新值。
静态局部变量在程序执行到该对象的声明处首次初始化,如果没有显示初始化就会默认初始化,在以后的函数调用中就不在初始化了。静态局部变量始终驻留在全局数据区,知道程序运行结束,而且作用域为局部作用域,处其定义所在的函数外不可以调用他。
#include <iostream>
using namespace std;
void fun();
int main()
{
fun();
fun();
fun();
return 0;
}
void fun()
{
static int n = 10;
cout<<n<<endl;
n++;
}
代码分析:因为在函数fun()中局部变量n是静态的,所以函数退出后他还继续存储在全局数据区。因此输出结果是10,11,12.
3.静态函数
在函数的返回类型前加上关键字static,函数就被定义为静态函数,静态函数只能在当前文件中可见,不能被其他文件调用。因此不会和其他文件中相同名字的函数发生冲突。
#include <iostream>
using namespace std;
static void fun(); //声明静态函数
int main()
{
fun();
return 0;
}
void fun() //定义静态函数
{
int n = 10;
cout<<n<<endl;
}
代码分析:此文件中定义的静态函数只能在此文件中可见,其他文件无法调用。
面向对象的static
所谓的面向对象的static就是在类中的数据成员或成员函数加上关键字static
1.静态数据成员
在类中数据成员之前加上关键字static,该数据成员就是类中的静态数据成员。
对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当成类的成员,无论这个类的对象定义多少个,静态数据成员在程序中只有一份拷贝,由该类型的所有对象共享访问,静态数据成员只分配一次内存,供所有对象使用。静态数据成员存储在全局数据区,静态数据成员在定义时分配内存,因此不能在类声明中定义。静态成员在类体外初始化而且不加static关键字,初始化是用作用域运算符来表明他所属的类。
静态数据对象主要用在各个对象都有相同的某个属性时。比如存款类,所有的实例对象都有相同的利息。
#include <iostream>
using namespace std;
class Myclass
{
public:
Myclass(int a,int b,int c);
void GetSum();
private:
int a,b,c;
static int Sum; //声明 静态数据成员
};
int Myclass::Sum = 0; //定义并初始化静态数据成员
Myclass::Myclass(int x,int y,int z)
{
a = x;
b = y;
c = z;
Sum += a + b + c;
}
void Myclass::GetSum()
{
cout<<"Sum = "<<Sum<<endl;
}
int main()
{
Myclass M(1,2,3);
M.GetSum();
Myclass N(4,5,6);
N.GetSum();
M.GetSum();
return 0;
}
代码分析:类Myclass有两个实例对象M,N,因为Sum是静态数据成员,是被所有对象共享的,所以输出结果是6,21,21.
2.静态成员函数
静态成员函数为类的全部服务而不是为某一个类的具体对象服务。静态成员函数跟静态数据成员一样,都是类的内部实现,属于类定义的一部分。普通的成员函数一般都隐含一个this指针,this指针指向类的对象本身,因为普通成员函数总是属于某个类的具体对象。但是由于静态成员函数不与任何对象有联系,因此他不具有this指针。所以他无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数。他只能访问其他的静态成员函数和静态数据成员。但是非静态成员函数可以调用静态成员函数,也可以访问静态数据成员。
#include <iostream>
using namespace std;
class Myclass
{
public:
Myclass(int a,int b,int c);
static void GetSum();//声明静态成员函数
private:
int a,b,c;
static int Sum; //声明 静态数据成员
};
int Myclass::Sum = 0; //定义并初始化静态数据成员
Myclass::Myclass(int x,int y,int z)
{
a = x;
b = y;
c = z;
Sum += a + b + c; //非静态成员函数可以访问静态数据成员
}
void Myclass::GetSum() //静态成员函数的实现
{
//cout<<a<<endl; //error:静态成员函数不能访问非静态数据成员
cout<<"Sum = "<<Sum<<endl;
}
int main()
{
Myclass M(1,2,3);
M.GetSum();
Myclass N(4,5,6);
N.GetSum();
M.GetSum();
return 0;
}
- 总结
- 首先是隐藏,使用关键字static是在一个文件中定义的内容不被其他文件调用,同时可以防止在其他文件中定义了相同名字的成员而引起冲突。(一般在定义全局变量时会考虑这点,把全局变量定义成静态的)
- 当要保持函数中局部变量的值的持久性,可以将局部变量定义为静态局部变量。
- 当某个类的对象拥有相同的属性时,可以将该属性定义为静态的,这样该属性只定义一次,不需要为每个对象都拷贝一份,节省了空间。在面向对象的编程中巧妙的运用关键字static可以起到优化程序的效果.