从 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 的意思(对于非本地、非成员变量)。
你需要了解两件事才能理解这里发生的事情。
在 C++ 中,头文件只是 "copy-pasted" 直接或间接包含它们的每个 .cpp 文件的文本。预处理后的源代码为"compilation unit",所以基本上可以认为一个.cpp文件就是一个编译单元。
static
全局变量(不要与 classes 的静态成员变量混淆,又名 class 变量,它们与非静态变量本质上相同全局变量...)在定义它们的编译单元内可见。如果在两个编译单元中定义静态全局变量,它们是完全独立的变量,并且不会干扰(它们的名称在编译单元外也不可见) .所以,除非你知道你确实想要多个 .cpp 文件中的变量的单独副本(非常罕见),否则你不应该将静态全局变量放在 .h 文件中(extern
在 .cpp 中定义的全局变量声明文件是您通常想要的 .h 文件)。
现在当你把这两个东西结合起来,你会发现.h文件中定义的静态变量与.cpp文件中定义的静态变量没有什么不同。如果 .h 文件包含在多个 .cpp 文件中,您将获得变量的多个副本,使用哪个副本取决于它是哪个 .cpp 文件(直接或通过包含)。
你有两个.cpp文件,它们都在这里定义了同一个静态变量,所以它们有两个副本,在这些文件中编译的代码将使用不同的变量。
现在这里有额外的怪癖。如果您定义一个成员函数,包括构造函数,内联(当您在 class 内定义它时隐式发生,如果您在 .h 文件中但在 class 之外定义它,则必须使用 inline
关键字),那么每个 .cpp 文件都会得到该函数的不同副本。现在你作为程序员承诺它们将是相同的,这就是 inline
的意思(它与内联优化只有一点点关系)。如果您有多个相同构造函数的副本(在 .h 文件中定义),并且它们实际上访问了 不同的 静态变量,那么它们就不一样了,您就违背了诺言。不要那样做!
我正在尝试从 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 的意思(对于非本地、非成员变量)。
你需要了解两件事才能理解这里发生的事情。
在 C++ 中,头文件只是 "copy-pasted" 直接或间接包含它们的每个 .cpp 文件的文本。预处理后的源代码为"compilation unit",所以基本上可以认为一个.cpp文件就是一个编译单元。
static
全局变量(不要与 classes 的静态成员变量混淆,又名 class 变量,它们与非静态变量本质上相同全局变量...)在定义它们的编译单元内可见。如果在两个编译单元中定义静态全局变量,它们是完全独立的变量,并且不会干扰(它们的名称在编译单元外也不可见) .所以,除非你知道你确实想要多个 .cpp 文件中的变量的单独副本(非常罕见),否则你不应该将静态全局变量放在 .h 文件中(extern
在 .cpp 中定义的全局变量声明文件是您通常想要的 .h 文件)。
现在当你把这两个东西结合起来,你会发现.h文件中定义的静态变量与.cpp文件中定义的静态变量没有什么不同。如果 .h 文件包含在多个 .cpp 文件中,您将获得变量的多个副本,使用哪个副本取决于它是哪个 .cpp 文件(直接或通过包含)。
你有两个.cpp文件,它们都在这里定义了同一个静态变量,所以它们有两个副本,在这些文件中编译的代码将使用不同的变量。
现在这里有额外的怪癖。如果您定义一个成员函数,包括构造函数,内联(当您在 class 内定义它时隐式发生,如果您在 .h 文件中但在 class 之外定义它,则必须使用 inline
关键字),那么每个 .cpp 文件都会得到该函数的不同副本。现在你作为程序员承诺它们将是相同的,这就是 inline
的意思(它与内联优化只有一点点关系)。如果您有多个相同构造函数的副本(在 .h 文件中定义),并且它们实际上访问了 不同的 静态变量,那么它们就不一样了,您就违背了诺言。不要那样做!