转自:http://blog.csdn.net/wanglongfei_hust/article/details/10011503

static关键字有三种使用方式,其中前两种只指在C语言中使用,第三种在C++中使用。

1. 局部静态变量(C)

2. 外部静态变量/函数(C)

3. 静态数据成员/成员函数(C++)

一、 局部静态变量

局部变量按照存储形式可以分为三种,分别是auto、static、register。

与auto类型(普通)局部变量相比,static有三点不同:

1. 存储空间分配不同

auto类型分配在栈上,属于动态存储类别,占动态存储空间,函数调用结束后自动释放;

static类型分配在静态存储区,在程序整个运行期间都不释放;

两者作用域相同,但是生存期不同。

2. static局部变量在初次运行时进行初始化工作,且只初始化一次。

3. 对于局部静态变量,如果不赋初值,编译期会自动赋初值0或者空;

auto类型的初值是不确定的。

对于C++的类对象例外,class的对象实例如果不初始化,则会自动调用默认构造函数,不管是不是static类型。

特点:static局部变量的“记忆性”与生存期的“全局性”

所谓“记忆性”是指在两次函数调用时,在第二次调用进入时,能保持第一次调用退出时的值。

示例程序一

  1. #include <iostream>
  2. using namespace std;
  3. void staticLocalVar()
  4. {
  5. static int a = 0;
  6. cout<<"a="<<++a<<endl;
  7. }
  8. int main()
  9. {
  10. staticLocalVar();   // a=1
  11. staticLocalVar();   // a=2
  12. system("pause");
  13. return 0;
  14. }

运行结果:

a=1

a=2

请按任意键继续. . .

应用:利用“记忆性”记录函数调用的次数(示例程序一)
利用生存期的”全局性“改善return a pointer / reference to a local object的问题,local object的问题在于退出函数时,生存期就结束,局部变量就会被销毁;利用static就可以延长局部变量的生存期。

注意事项:
1. “记忆性”是程序运行很重要的一点就是可重复性,而static变量的“记忆性”破坏了可重复性,造成不同时刻同一函数的运行结果不同。

2. “生存期”全局性和唯一性。 普通的局部变量在栈上分配空间,因此每次调用函数时,分配的空间都可能不一样,而static具有全局唯一性的特点,每次调用时都指向同一块内存,这就造成一个很重要的问题---不可重入性!!!

在多线程或者递归程序中要特别注意。

二、 外部静态变量/函数

在C中static的第二种含义:用来表示不能被其它文件访问的全局变量和函数。

此处static的含义是指对函数的作用域仅仅局限于本文件(所以又称为内部函数)。

注意:对于外部(全局)变量,不论是否有static限制,它的存储区域都是在静态存储区,生存期都是全局的,此时的static只是起作用域限制作用,限制作用域在本文件内部。

使用内部函数的好处是:不同的人编写不同的函数时,不用担心函数同名问题。

示例程序二

  1. //file1.cpp
  2. static int varA;
  3. int varB;
  4. extern void funA()
  5. {
  6. }
  7. static void funB()
  8. {
  9. }
  10. //file2.cpp
  11. extern int varB; // 使用file1.cpp中定义的全局变量
  12. extern int varA; // 错误! varA是static类型, 无法在其他文件中使用
  13. extern void funA(); // 使用file1.cpp中定义的函数
  14. extern void funB(); // 错误! 无法使用file1.cpp文件中static函数

三、 静态数据成员/成员函数(C++特有)

C++重用了这个关键字,它表示属于一个类而不是属于此类的任何特定的对象的变量和函数。

静态类成员包括静态数据成员和静态函数成员。

1. 静态数据成员

类体中的数据成员的声明前加上static关键字,该数据成员就成为了该类的静态数据成员。和其他数据成员一样,静态数据成员也遵守public/protected/private访问规则。同时静态数据成员还具有以下特点。

1) 静态数据成员的定义

静态数据成员实际上是类域中的全局变量。所以,静态数据成员的定义(初始化)不应该被放在头文件中。其定义方式与全局变量相同。举例如下:

  1. xxx.h文件
  2. class base
  3. {
  4. private:
  5. static const int _i;    //声明,标准c++支持有序类型在类体中初始化,但vc6不支持。
  6. };
  7. xxx.cpp文件
  8. const int base::_i = 10;    //定义(初始化)时不受private和protected访问限制.

注:不要试图在头文件中定义(初始化)静态数据成员。在大多数情况下,这会引起重复定义。即使加上#ifndef  #define  #endif或者#pragma once也不行。

2) 静态数据成员被类的所有对象所共享,包括该类的派生类的对象。

  1. #include <iostream>
  2. using namespace std;
  3. class base
  4. {
  5. public:
  6. static int _num;    //声明
  7. };
  8. int base::_num = 0; //静态数据成员的真正定义
  9. class derived : public base
  10. {
  11. };
  12. int main()
  13. {
  14. base a;
  15. derived b;
  16. a._num++;
  17. cout<<"base class static data number _num is "<<a._num<<endl; // 1
  18. b._num++;
  19. cout<<"derived class static data number _num is "<<b._num<<endl;// 2
  20. system("pause");
  21. return 0;
  22. }

3) 静态数据成员可以成为成员函数的可选参数,而普通数据成员则不可以。

  1. class base
  2. {
  3. public:
  4. static int _staticVar;
  5. int _var;
  6. void foo1(int i = _staticVar);//正确,_staticVar为静态数据成员
  7. void foo2(int i = _var);//错误,_var为普通数据成员
  8. };

4)★静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以。普通数据成员的只能声明为所属类类型的指针或引用。举例如下:

  1. class base
  2. {
  3. public:
  4. static base _object1;//正确,静态数据成员
  5. base  object2;//错误
  6. base *pObject;//正确,指针
  7. base &mObject;//正确,引用
  8. };

5)  静态数据成员的值在const成员函数中可以被合法的改变。举例如下:

  1. class base
  2. {
  3. public:
  4. base()
  5. {
  6. _i = 0;
  7. _val = 0;
  8. }
  9. mutable int _i;
  10. static int _staticVal;
  11. int _val;
  12. void test() const
  13. {
  14. _i++;//正确,mutable数据成员
  15. _staticVal++;//正确,static数据成员
  16. _val++;//错误
  17. }
  18. };
  19. int   base::_staticVal = 0;

2. 静态成员函数

1).静态成员函数的地址可用普通函数指针储存,而普通成员函数地址需要用类成员函数指针来储存。举例如下:

  1. class base
  2. {
  3. static int func1();
  4. int func2();
  5. };
  6. int (*pf1)() = &base::func1;        //普通的函数指针
  7. int (base::*pf2)() = &base::func2;  //成员函数指针

2).静态成员函数不可以调用类的非静态成员。因为静态成员函数不含this指针。  
3).静态成员函数不可以同时声明为   virtual、const、volatile函数。举例如下:

  1. class base
  2. {
  3. virtual static void func1();//错误
  4. static void func2() const;//错误
  5. static void func3() volatile;//错误
  6. };

最后要说的一点是,静态成员是可以独立访问的,也就是说,无须创建任何对象实例就可以访问。

最新文章

  1. LogBack简易教程
  2. 【转载】mysql慢查询
  3. RDVTabBarController的基本使用 以及tabbar的防止双点击方法
  4. c++ 头文件
  5. JAVA线程池的分析和使用
  6. 解读Unity中的CG编写Shader系列四(unity中的圆角矩形shader)
  7. TCP连接的状态详解以及故障排查
  8. 解决 window server2008 r2 没有注册Ofiice组件的方法
  9. 在Windows下Mysql如何重置root用户密码
  10. 网络IPC:套接字之寻址
  11. iis post 请求.html文件报405
  12. cocos2dx 动画 二(iOS)
  13. linux系统怎么改为中文版(转)
  14. zabbix上监控docker
  15. JAVA 通过 Socket 实现 TCP 编程
  16. python内置函数与匿名函数
  17. centos6.7 配置MongoDB日志
  18. Atcoder Grand Contest 032
  19. 福州大学软件工程1816 | W班 第10次作业[软件工程实践总结]
  20. main函数和线程的关系

热门文章

  1. PyQt 5菜单和工具栏
  2. 视频编解码---x264用于编码,ffmpeg用于解码
  3. Java类的初始化与实例对象的初始化
  4. 新版台式机安装win7操作系统
  5. 两栏自适应布局,右侧div宽高不定
  6. Fiddler监控面板显示Server栏(Fiddler v5.0)
  7. App切图命名规范
  8. ecshop if多条件语句写法
  9. Centos内核参数
  10. sublime中开启表格插入