从 CPP 文件访问静态变量到其他头文件

Access static variable from CPP file to other header file

我正在尝试从 CPP 文件访问其他头文件中的静态变量。

"Boo.hpp"

#ifndef Boo_hpp
#define Boo_hpp

static int num;

class Boo
{
public:
    Boo()
    {
        num = 35;
    }
};

#endif /* Boo_hpp */

"Foo.hpp"

#ifndef Foo_hpp
#define Foo_hpp

class Foo
{
public:
    Foo();
};

#endif /* Foo_hpp */

"Foo.cpp"

#include "Foo.hpp"
#include "Boo.hpp"
#include <iostream>

Foo::Foo()
{
    std::cout << "Num : " << num << '\n';
}

"main.cpp"

#include <iostream>
#include "Foo.hpp"
#include "Boo.hpp"

int main()
{
    Boo boo;
    Foo foo;
}

我得到的结果:

Num : 0
Program ended with exit code: 0

我期望的结果:

Num : 35
Program ended with exit code: 0

如果我将 class Foo 的构造函数实现从 Foo.cpp 移动到 Foo.hpp,我的代码将按预期工作。

但是,我希望能够从 Foo.cpp 访问 num

我应该如何修复我的代码?

C/C++ 中全局变量的关键字 static 指示编译器将该符号限制为 当前 编译单元,即它声明的文件in. 将 static 声明放入头文件是一个巨大的陷阱,因为即使您在所有源文件中包含相同的头文件,每个文件都会收到自己的静态符号副本。

你想要的是 extern 关键字,它声明要在编译单元之间共享的符号,即 extern int num.

关于存储的更多阅读 class 说明符 here

包含 Boo.hpp 的所有 translation units 将具有 它们自己的 num 变量定义。没有其他 TU(翻译单元)具有相同的 num 变量。

这就是 static linkage storage modifier 的意思(对于非本地、非成员变量)。

你需要了解两件事才能理解这里发生的事情。

  1. 在 C++ 中,头文件只是 "copy-pasted" 直接或间接包含它们的每个 .cpp 文件的文本。预处理后的源代码为"compilation unit",所以基本上可以认为一个.cpp文件就是一个编译单元。

  2. static 全局变量(不要与 classes 的静态成员变量混淆,又名 class 变量,它们与非静态变量本质上相同全局变量...)在定义它们的编译单元内可见。如果在两个编译单元中定义静态全局变量,它们是完全独立的变量,并且不会干扰(它们的名称在编译单元外也不可见) .所以,除非你知道你确实想要多个 .cpp 文件中的变量的单独副本(非常罕见),否则你不应该将静态全局变量放在 .h 文件中(extern 在 .cpp 中定义的全局变量声明文件是您通常想要的 .h 文件)。

现在当你把这两个东西结合起来,你会发现.h文件中定义的静态变量与.cpp文件中定义的静态变量没有什么不同。如果 .h 文件包含在多个 .cpp 文件中,您将获得变量的多个副本,使用哪个副本取决于它是哪个 .cpp 文件(直接或通过包含)。

你有两个.cpp文件,它们都在这里定义了同一个静态变量,所以它们有两个副本,在这些文件中编译的代码将使用不同的变量。


现在这里有额外的怪癖。如果您定义一个成员函数,包括构造函数,内联(当您在 class 内定义它时隐式发生,如果您在 .h 文件中但在 class 之外定义它,则必须使用 inline 关键字),那么每个 .cpp 文件都会得到该函数的不同副本。现在你作为程序员承诺它们将是相同的,这就是 inline 的意思(它与内联优化只有一点点关系)。如果您有多个相同构造函数的副本(在 .h 文件中定义),并且它们实际上访问了 不同的 静态变量,那么它们就不一样了,您就违背了诺言。不要那样做!