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

时间:2016-03-22 06:21:27

标签: c++ header initialization

编辑:正确的功能名称,并添加了#pragma一次

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

A.H

#pragma once
static int testNumber = 10;
void changeTestNumber();

A.cpp

#pragma once
#include "A.h"

void changeTestNumber()
{
    testNumber = 15;
} 

B.h

#pragma once
#include "A.h"
// some other stuff

B.cpp

#pragma once
#include "B.h"
// some other stuff

的main.cpp

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

int main(){

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

return 0;
}

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

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

提前致谢!

3 个答案:

答案 0 :(得分:5)

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

如果你改变:

static int testNumber = 10;

A.h文件中:

extern int testNumber;

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

#include "A.h"
int testNumber = 10;

现在继续运行:

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;
}

务必修复功能名称!

答案 1 :(得分:3)

Goodies和其他人肯定是正确的,但让我再提前一步:

  1. static将定义定义为翻译单元的本地定义。因此,在标题中定义静态全局变量将导致与包含它的翻译单元一样多的副本。除非那不是你想要的那不是那种方式

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

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

  4. 现在,2 nd 案件有两个限制:

    • 它会强制您使用可编译的源来实例化全局对象,即使在您提供模板库(或“仅标题”库)的情况下,也可以根据需要使交付更加复杂
    • 它暴露于所谓的全局初始化惨败:如果初始化一个全局对象,其值取自其他地方定义的其他全局对象,因为C ++不会授予它们的构造顺序(最终属于链接器的工作方式),您可能无法正确初始化和销毁​​全局对象。

    为避免这一切,请考虑

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

    您可以在标题中定义全局值,方法是将它们设置为函数的局部值:例如

    inline int& global_val() //note the &
    { static int z = 0; return z; }
    

    唯一缺点是每次访问时始终放置()

    由于本地值是唯一的并且在调用时被实例化,这将确保,如果全局变量之间存在依赖关系(将int z=0视为int z=something_else()),它们将按照它们的顺序创建即使在递归和多线程的情况下(从c ++ 14开始)

    ,也需要以相反的顺序销毁

    考虑到C ++向泛型和函数范式的演变,并考虑将所有源放在单个编译单元中比连接多个源更有时间...考虑不使用全局变量,而是用内联instatiator 功能。

    约2年后编辑:

    C ++ 17最终为变量声明引入了内联指令,就像函数扩展的语法快捷方式一样。

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

    inline const float PI = 3.14159;
    inline int goodies = 25;
    

答案 2 :(得分:1)

A.H

extern int testNumber;
void changeNumber();

A.cpp

#include "A.h"

int testNumber = 10;

void changeTestNumber()
{
    testNumber = 15;
} 

B.h

#include "A.h"
// some other stuff

B.cpp

#include "B.h"
// some other stuff

的main.cpp

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

int main(){

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

    return 0;

}

请尝试那样。