在头文件C++中初始化变量

rem*_*emi 4 c++ initialization header

编辑:正确的函数名称,并添加#pragma一次

这是我的问题的一个非常强大的简化,但如果我这样做:

#pragma once
static int testNumber = 10;
void changeTestNumber();
Run Code Online (Sandbox Code Playgroud)

A.cpp

#pragma once
#include "A.h"

void changeTestNumber()
{
    testNumber = 15;
} 
Run Code Online (Sandbox Code Playgroud)

BH

#pragma once
#include "A.h"
// some other stuff
Run Code Online (Sandbox Code Playgroud)

B.cpp

#pragma once
#include "B.h"
// some other stuff
Run Code Online (Sandbox Code Playgroud)

main.cpp中

#pragma once
#include "B.h"
#include <iostream>

int main(){

changeTestNumber();
std::cout<<testNumber<<std::endl;

return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么我在呼叫时没有得到testNumber = 15?当我使用包含在我的包含标题的标题中的函数时,会发生什么?如果我删除在从INT testNumber,我会得到一些错误,我的testNumber被初始化两次.

当我这样做时,我的标题编译了两次吗?

提前致谢!

Goo*_*ies 5

除了明显不正确的命名(我假设这只是匆忙创建一个类似的例子并且不是代码中的实际问题),你需要extern在.h/.hpp文件中声明变量.你不能拥有一个extern变量,static因为(一个)use的使用static是将变量包含在一个.cpp文件中.

如果你改变:

static int testNumber = 10;
Run Code Online (Sandbox Code Playgroud)

在你的A.h文件中:

extern int testNumber;
Run Code Online (Sandbox Code Playgroud)

然后在你的A.cpp文件中执行以下操作:

#include "A.h"
int testNumber = 10;
Run Code Online (Sandbox Code Playgroud)

现在继续运行:

int main() {
    //changeNumber();
    std::cout << testNumber << std::endl; // prints 10
    changeTestNumber(); // changes to 15
    std::cout << testNumber << std::endl; // prints 15
    std::cin.ignore();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

务必修复功能名称!


Emi*_*lia 5

好东西和其他人当然是正确的,但让我再向前迈出一步:

  1. static使定义本地化到翻译单元。因此,在标头中定义静态全局变量将产生与包含它的翻译单元一样多的副本。除非那不是你想要的,否则不是这样

  2. extern告诉编译器全局变量存在于某处,但未定义,必须在链接阶段进行搜索。为了使链接器成功,您需要在某处定义它(通常是一个更有意义的源文件)

  3. 省略它们两者将导致“多重定义”链接器错误,其中多个源包含一个标头。

现在,第二种情况有两个限制:

  • 它迫使您拥有一个可编译的源来实例化全局对象,即使您提供的是模板库(或“仅标头”库),从而使交付根据需要变得更加复杂
  • 它暴露于所谓的全局初始化失败:如果您使用从其他地方定义的其他全局对象中获取的值初始化全局对象,因为 C++ 不授予它们的构造顺序(最终属于链接器的工作方式),您可能无法正确初始化和销毁​​全局对象。

为了避免这一切,请考虑

  • 一个全局定义的函数,如果明确声明为inline可以链接更多次并且
  • 模板函数以及类内定义的成员函数默认是内联的
  • 静态本地对象仅在第一次遇到时创建一次

您可以通过将全局值设置为函数的本地静态值来定义标头中的全局值:例如

inline int& global_val() //note the &
{ static int z = 0; return z; }
Run Code Online (Sandbox Code Playgroud)

唯一的缺点是您必须始终()在每次访问时放置一个。

由于本地值是唯一的并且在调用时实例化,这将确保,如果全局变量之间存在依赖关系(认为是int z=0as int z=something_else()),它们将按照需要的顺序创建并以相反的顺序销毁,即使在递归和多线程 (c++14 起)

考虑到 C++ 向泛型和函数范式的演变,并考虑到将所有源放在单个编译单元中有时比链接多个源更可取……考虑不使用全局变量,而是用内联的 instatiator函数替换它们。


大约2年后编辑:

C++17 终于为变量声明引入了 inline 指令,作为函数扩展的语法快捷方式。

所以 - 今天 - 你可以简单地写

inline const float PI = 3.14159;
inline int goodies = 25;
Run Code Online (Sandbox Code Playgroud)