C++中的静态static

上一篇:C++如何写一个C++类

[下一篇: C++类和结构体中的静态static]

1. 概述

本篇主要讨论C++中的static(静态)关键字。static关键字在C++中有两个意思,这取决于上下文。第一种意思是在类或结构体外部使用static关键字。第二种意思是在类或结构体内部使用static关键字。

直白来说,类或结构体外面的static,意味着我们声明为static的符号,链接将只是在内部,这意味着它只能对你定义他的翻译单元可见。

然而类或结构体内部的static,意味着该变量实际上将与类的所有实例共享内存,这意味着该静态变量在你在类中创建的所有实例中,静态变量只有一个实例。类似的事情也适用于类中的静态方法。在类中,没有实例会传递给该方法。

这里我们不深入讨论静态static在类或结构体范围内的实际含义,本篇我们只关注在类和结构体外部的静态static。

2. 案例

1. 准备项目

准备一个简单的项目,我们有一个main.cpp文件,内容如下。

2. 开始案例

我们创建一个Static.cpp文件

我们要做的就是定义一个静态变量,我将使用惯例s_来表示这个变量是静态的,并给这个静态变量赋值为5,static int s_Variable = 5;

它和其他变量一样,但它前面有static关键字,这到底是什么意思呢?

它的意思是,这个变量只会在这个翻译单元内部链接。有关链接的内容可参考编译器是如何工作的链接器是如何工作的

静态变量或函数意味着,当需要将这些函数或变量与实际定义的符号链接时,链接器不会在这个翻译单元的作用域之外寻找那个符号定义。

下面用例子来解释下。

我们在Static.cpp文件中创建了一个静态变量s_Variable,并赋值了5。

然后我们到另一个cpp文件,也就是另一个翻译单元,main.cpp文件。

我们要给它一个和Static.cpp文件中静态变量一样名字的变量并赋值为10,如下

如果我们试着来打印这个变量

单文件编译main.cpp文件 ctrl + F7

可以看到,编译成功,不会有任何问题。

如果我们F5运行我们的代码

可以看到,控制台打印了10。

然而,如果我们回到Static.cpp文件中

将static关键字去掉

然后编译我们的项目,因为编译项目会有链接阶段

可以看到,我们会得到一个链接错误,因为这个s_Variable变量已经在另一个翻译单元重定义了。所以我们不能有两个同名的全局变量。

一种修改的方法是,让main.cpp文件中s_Variable变量的实际指向Static.cpp文件中s_Variable变量。我们可以这样做,去掉main.cpp文件中s_Variable的赋值,并标识这个变量为extern

使用extern,意味着它会在外部翻译单元中寻找这个s_Variable变量。这被称为external linkageexternal linking

如果我们F5运行我们的代码

可以看到我们得到的值是5。因为他引用了Static.cpp中的s_Variable变量。

然而,如果我们在Static.cpp文件中的s_Variable声明为static。

这有点像在类中声明一个私有变量,其他所有的翻译单元都不能看到Static.cpp中s_Variable变量。链接器在全局作用域下,将不会看到这个变量。

也就是说,如果我们回到main.cpp文件

编译我们的项目

可以看到我们会得到一个无法解析的外部命令的错误。这是因为它在任何地方都找不到名称为s_Variable的整型变量。因为我们有效的标记了Static.cpp中s_Variable这个变量为私有的。

如果我们回到Static.cpp文件,和之前一样,我们再声明一个函数Function。

然后我们在main.cpp文件中也声明一个具有相同签名的函数Function

如果我们现在编译我们的项目。

会看到一个链接错误1 个无法解析的外部命令,这是前面测试s_Variable变量时的错误。我们去掉main.cpp文件中s_Variable相关变量

我们在编译我们的项目

可以看到,我们将在链接阶段得到一个重复的符号错误,因为链接器找到了两个Function函数。

我们切换到Static.cpp文件,在Function函数前面加上static

我们编译项目

可以看到编译通过了,因为当链接开始时,链接器根本不会看到Static.cpp中的这个静态的函数。所以我们不会得到任何错误。

这就是C++中静态的全部含义。当你在类和结构体之外使用静态时,意味着,当你声明静态函数或静态变量时,这些静态函数和静态变量只会在它们被声明的C++文件中被看到。

如果你想在头文件中声明一个静态变量,并将该头文件包含在两个不同的C++文件中。那就会我们现在的例子一样,就是在两个翻译单元中都声明了相同的s_Variable变量为静态变量。因为,当你包含那个头文件时,它会复制所有内容并将其粘贴到C++文件中,你所做的是将一个静态变量放到两个不同的翻译单元中。

至于为什么要用static,考虑下为什么要在类中使用private?如果我们不需要变量是全局变量,那我们就应该尽可能的多使用静态变量。因为一旦我们在全局作用域下声明东西的时候,也就是没有static修饰时,那么链接器会跨编译单元进行链接,这就意味这我们已经创建了一个全局的变量。如果我们创建一个变量variable,而且是在全局作用域下,那么这个变量variable,将可以在任何地方使用,这可能会导致一些非常糟糕的bug。

所以重点是,要让函数和变量标记为静态的,除非我们真的需要它们跨翻译单元进行链接。

上一篇:C++如何写一个C++类

[下一篇: C++类和结构体中的静态static]

[下一篇: C++类和结构体中的静态static]:

相关推荐
lqqjuly2 小时前
特殊的“Undefined Reference xxx“编译错误
c语言·c++
冰红茶兑滴水3 小时前
云备份项目--工具类编写
linux·c++
刘好念3 小时前
[OpenGL]使用 Compute Shader 实现矩阵点乘
c++·计算机图形学·opengl·glsl
酒鬼猿4 小时前
C++进阶(二)--面向对象--继承
java·开发语言·c++
姚先生974 小时前
LeetCode 209. 长度最小的子数组 (C++实现)
c++·算法·leetcode
小王爱吃月亮糖5 小时前
QT开发【常用控件1】-Layouts & Spacers
开发语言·前端·c++·qt·visual studio
aworkholic5 小时前
opencv sdk for java中提示无stiching模块接口的问题
java·c++·opencv·jni·opencv4android·stiching
程序员老冯头5 小时前
第十六章 C++ 字符串
开发语言·c++
Xenia2235 小时前
复习篇~第二章程序设计基础
c++·算法
想睡觉 . 我也想睡觉 .5 小时前
【C++算法】1.【模板】前缀和
开发语言·c++·算法