C++ static关键字

static关键字可用于声明全局范围、命名空间范围和类范围变量和函数。 静态变量还可在本地范围声明。

先介绍几个概念:

  1. 静态持续时间,在程序启动时分配对象或变量,并在程序结束时释放对象或变量。

  2. 外部链接,变量的名称在用于声明变量的文件的外部是可见的。

  3. 内部链接,名称在用于声明变量的文件的外部是不可见的。

默认情况下,在全局命名空间中定义的对象或变量具有静态持续时间和外部链接。

static 关键字常用于以下情况:

  1. 在全局和/或命名空间范围 (在单个文件范围内声明变量或函数时,) static 关键字指定变量或函数为内部链接,即外部文件无法引用该变量或函数。在声明变量时,变量具有静态持续时间,并且除非您指定另一个值,否则编译器会将变量初始化为 0。
  2. 在函数中声明变量时, static 关键字指定变量只初始化一次,并在之后调用该函数时保留其状态。
  3. 在类内声明中声明数据成员时, static 关键字指定该类的所有实例共享该变量的副本。 必须在文件范围内定义静态数据成员。
  4. 在类声明中声明成员函数时, 关键字指定该函数由类的所有实例 static 共享。 静态成员函数无法访问实例成员,因为该函数没有隐式 this 指针。 若要访问实例成员,请使用作为实例指针或引用的参数来声明函数。
  5. 不能将联合成员声明为静态的。 但是,必须显式声明全局声明的匿名联合 static

以上前两条与面向对象(类)无关,也就是说在 C 中 static 同样有这些特性,而后三条则是针对类的,在 C++ 中才有这些特性。

C中的static

本小节介绍 C 中 static 关键字的作用,即不包含 C++ 中引入面向对象的特性(类)之后 static 的作用,该部分将在下一小节介绍。

内部链接

函数,变量均可被 static 修饰来实现内部链接。当同时编译多个文件时,所有未加 static 前缀的全局变量和函数默认都是外部链接的。举例来说明。同时编译两个源文件,一个是 hello_a.c,另一个是 main.c

// hello_a.c
#include <stdio.h>
char a = 'A'; // a.c 文件内的全局变量
void printHello()
{printf("Hello\n");
}
// main.c
#include <stdio.h>
void msg();     // 外部方法不声明会报警告
int main()
{extern char a; // 外部变量必须先用 extern 关键字声明printf("%c \n", a);printHello();return 0;
}

编译运行:

gcc main.c  hello_a.c
./a.out

输出:

A
Hello

为什么在 hello_a.c 中定义的全局变量 a 和函数 printHello 能在 main.c 中使用?前面说过,所有未加 static 前缀的全局变量和函数都都是外部链接的,其它的源文件也能访问。此例中,a 是全局变量,printHello 是函数,并且都没有加 static 前缀,因此对于另外的源文件 main.c 是可见的。

如果加了 static,就会对其它源文件隐藏。例如在 a 和 printHello 的定义前加上 static,main.c 就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。static 可以修饰函数和变量,将其对其他源文件隐藏起来,从而避免命名冲突。对于函数来讲,static 的作用仅限于该隐藏功能。

保持变量内容的持久

static的第二个作用是保持变量内容的持久,即static变量中的记忆功能和全局生存期。

存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。之后再次运行到含有 static 关键字的初始化语句时不会再执行该语句。共有两种变量存储在静态存储区:全局变量和 static 变量,只不过和全局变量比起来,static 可以控制变量的可见范围。

PS:如果作为 static 局部变量在函数内定义,它的生存期为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。

在下面的例子中,nStatic的值仅在初次调用 showstat 函数时初始化,之后在每次调用showstat函数时,nStatic的值都是保持的(而非重新初始化)。

// static1.cpp
#include <iostream>using namespace std;
void showstat( int curr ) {static int nStatic;    // nStatic的值仅在初次调用时初始化,之后在每次调用showstat函数时,// nStatic的值都是保持的nStatic += curr;cout << "nStatic is " << nStatic << endl;
}int main() {for ( int i = 0; i < 5; i++ )showstat( i );
}

运行结果:

nStatic is 0
nStatic is 1
nStatic is 3
nStatic is 6
nStatic is 10

综合以上两点,有:

  • 把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围
  • 把局部变量(函数内)改变为静态变量后是改变了它的存储方式,从而改变了它的生存期

也就是说 static 这个关键字在不同的地方所起的作用是不同的。

默认初始化为0

static的另一个作用是默认初始化为0。其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加‘\0’;太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是 ‘\0’。不妨做个小实验验证一下。

#include <stdio.h>int a;int main()
{int i;static char str[10];printf("integer: %d; string: (begin)%s(end)\n", a, str);return 0;
}

输出:

integer: 0; string: (begin)(end)

C++中的static

本小节主要是介绍在 C++ 中引入了面向对象的特性(类)之后,static 关键字的一些用途。当然之前的 C 中的 static 在 C++ 中也是成立的。

在类中声明 static 变量或者函数时,初始化时使用作用域运算符 :: 来标明它所属类。静态数据成员是类的成员,而不是对象的成员,这样就出现以下作用:

  1. 使用 static 关键字来修饰成员函数或变量,是指成为静态成员函数或变量。

  2. 类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据和静态成员函数。

  3. static 关键字不能修饰虚函数。

  4. 由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊 ,变量地址是指向其数据类型的指针 ,函数地址类型是一个“nonmember 函数指针”。

  5. 由于静态成员函数没有this指针,所以就差不多等同于 nonmember 函数,结果就产生了一个意想不到的好处:成为一个callback函数,使得我们得以将C++和C-based X W indow系统结合,同时也成功的应用于线程函数身上。 (这条没遇见过)

  6. static 并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问时间,节省了子类的内存空间。

  7. 静态数据成员是静态存储的,所以必须对它进行初始化。 (程序员手动初始化,否则编译时一般不会报错,但是在Link时会报错误)

  8. 静态成员初始化与一般数据成员初始化不同:

    • 声明在类内,初始化赋值在类外;

    • 初始时赋值前面不加 static,以免与一般静态变量或对象相混淆;

    • 初始化时赋值不加该成员的访问权限控制符private,public等;

    • 初始化时赋值使用作用域运算符 :: 来标明它所属类;

    所以我们得出静态数据成员初始化的格式:<数据类型><类名>::<静态数据成员名>=<值>如:int myClass::num = 10,在后面会有例子;

  9. 为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志;

  10. 不论在类内声明的还是在成员函数中声明的 static 变量,都是整个类的所有实例对象共享一份副本。

以下是例程:

类内声明的static变量

// static2.cpp
#include <iostream>using namespace std;
class CMyClass {public:static int m_i;
};int CMyClass::m_i = 0;
CMyClass myObject1;
CMyClass myObject2;int main() {cout << myObject1.m_i << endl;cout << myObject2.m_i << endl;myObject1.m_i = 1;cout << myObject1.m_i << endl;cout << myObject2.m_i << endl;myObject2.m_i = 2;cout << myObject1.m_i << endl;cout << myObject2.m_i << endl;CMyClass::m_i = 3;cout << myObject1.m_i << endl;cout << myObject2.m_i << endl;
}

结果输出:

0
0
1
1
2
2
3
3

CMyClass 内的 static 变量 m_i 是整个类共享的,在该类的每个对象 myObject1myObject2 中都一样。

成员函数内声明的static变量

// static3.cpp
#include <iostream>
using namespace std;
struct C {void Test(int value) {static int var = 0;if (var == value)cout << "var == value" << endl;elsecout << "var != value" << endl;var = value;}
};int main() {C c1;C c2;c1.Test(100);c2.Test(100);
}

结果输出:

var != value
var == value

Ref:

cnblogs.com/songdanzju/p/7422380.html

https://docs.microsoft.com/en-us/cpp/cpp/storage-classes-cpp?view=msvc-170

C++ static关键字相关推荐

  1. c语言中external,static关键字用法

    static用法: 在C中,static主要定义全局静态变量.定义局部静态变量.定义静态函数. 1.定义全局静态变量:在全局变量前面加上关键字static,该全局变量变成了全局静态变量.全局静态变量有 ...

  2. Java 静态变量,静态方法,静态常量(java static 关键字)

    Java 静态变量,静态方法,静态常量  就是变量 ,方法,常量前面添加了static 关键字 为什么要使用静态的呢 有时候在处理问题时会需要两个类在同一个内存区域共享一个数据, 不如现在 Main ...

  3. static关键字用法

    static关键字 1.修饰成员变量 在我们平时的使用当中,static最常用的功能就是修饰类的属性和方法,让他们成为类的成员属性和方法,我们通常将用static修饰的成员称为类成员或者静态成员,这句 ...

  4. Java中的static关键字的用法

    1.静态方法 static:通常在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法 声明为static的方法有以下几条限制: (1)它们仅能调用其他的static方法. (2 ...

  5. java的static关键字

    java的static关键字 静态变量和静态方法 static关键字最基本的用法是: 1.被static修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要new出一个类来 2.被static ...

  6. 面试季,Java中的static关键字解析

    点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大! static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面 ...

  7. c++语言static作用,详解c++中的 static 关键字及作用

    注:若没有特指是 静态成员时,默认都是普通成员: 1 类中的普通成员 类中的成员变量 和 成员函数 是分开存储的.其中, 1)每个对象都有独立的成员变量:成员变量可以存储在 栈空间.堆空间.全局数据区 ...

  8. static关键字了解解析

    什么是static关键字 static关键字我们经常接触,不过我们一直没有讨论过它到底是什么,有什么具体的作用,那static关键字是什么呢,有啥用呢? static是静态的意思,是一个修饰符,就像是 ...

  9. Java中的static关键字详解

    ** Java中的static关键字详解 ** 在一个类中定义一个方法为static,即静态的,那就是说无需本类的对象就可以调用此方法.调用一个静态方法就是 "类名.方法名" ,静 ...

  10. C++中的static关键字的总结

    C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static.前者应用于普通变量和函数,不涉及类:后者主要说明static在类中的作用. 1.面向过程设计中的st ...

最新文章

  1. 【MATLAB】基本绘图 ( 绘制多图 | 设置图形对话框在 Windows 界面的位置和大小 | 在一个图形上绘制多个小图形 )
  2. 飞鹤乳业CIO:移动化让企业品牌和消费者紧密连接
  3. python高阶函数和匿名函数
  4. sklearn自学指南(part30)--特征选择
  5. pc版android sd卡,告别瓶颈:安卓闪存(SD卡)I/O优化
  6. java 初始化和清楚_浅谈Java中的初始化和清理
  7. 基于Hadoop大数据分析应用场景与实战
  8. Flink的重启策略(RestartStrategy)实战
  9. 2021最新Android常用开源库总结,最强技术实现
  10. 微信小程序 基础 - 19 (登录后用户头像的更新)
  11. Hexo-Matery主题细致美化
  12. HDU Identity Card
  13. 【转】用IDCNN和CRF做端到端的中文实体识别
  14. 哈工大计算机网络物理层总结
  15. 通达信股票接口委托成功原理是什么?
  16. C语言练习(一球从M米高度自由下落,每次落地后返回原高度的一半,再落下,它在第N次落地时共经过多少米?反弹多高?)
  17. Unity 之 ShaderGraph 实现自发光和能量护盾效果入门级教程
  18. 跟着团子学SAP PS:CNS0 项目发货
  19. 淘宝怎么看历史价格走势曲线?
  20. C语言图书管理借阅系统——ncurses库的使用

热门文章

  1. ant编译web项目
  2. SpringBoot 整合Shiro Ehcache
  3. SpringBoot入门到精通_第5篇 _SpringBoot Actuator监控
  4. 使用html2Canvas将页面转化为canvas图片,最后长按保存到本地,史上最全 html2canvas 使用 踏坑之旅,没有之一
  5. 分布式应用,response导出error on submit request on future invoke、java.lang.OutOfMemoryError: Java heap space
  6. VBA 常用代码及自定义函数备忘
  7. 分区裁剪 oracle,[讨论]分区表并行和剪裁的困惑
  8. python模块里的函数及说明,Python模块 time与datetime模块的函数说明及使用实例
  9. jq之$(“[href]“)
  10. android paint 线宽_android Paint 设置线宽setStrokeWidth()的单位