【问题标题】:Why should I not initialize static variable in header? [duplicate]为什么我不应该在标头中初始化静态变量? [复制]
【发布时间】:2014-05-17 04:18:47
【问题描述】:

所以,假设我有这样的标题:

#ifndef BASECLASS_H
#define BASECLASS_H

class BaseClass
{
    public:
        static int getX(){return x;}
    private:
        static int x;
};

int BaseClass::x = 10;

#endif

我多次听说我不应该在头文件中初始化静态变量,而应该在 cpp.xml 中初始化。但是因为有守卫,所以BaseClass::x应该只有一份。所以我有点不明白我为什么要放

int BaseClass::x = 10; 

在 cpp 中。

【问题讨论】:

  • 这里的问题措辞和答案优于指定问题!

标签: c++ oop initialization static-initialization


【解决方案1】:

如果您在标头中执行此操作,一旦您从多个 CPP 文件中包含它,您就会收到多个定义错误。当您声明时,您实际上是在告诉编译器两件事

int BaseClass::x = 10;

首先,您要定义符号 BaseClass::x;其次,您告诉它您希望它具有初始值 10。根据One Definition Rule,这只能在您的程序中发生一次。

【讨论】:

  • 我想我开始明白了,但有什么方法可以证明吗?是不是我需要编写两个不同的程序,包括 BaseClass 并同时运行它们?
  • @user3496846 不,您只需要一个包含(至少)两个 cpp 文件的程序,这两个文件都包含您的标题。
【解决方案2】:

如果您考虑一下预处理器的实际作用,可能会更容易理解:它将所有包含的头文件的内容复制到 cpp 文件中并将其传递给编译器。

现在假设你有:

// In a.cpp
#include <baseclass.h>

// more code

// In b.cpp
#include <baseclass.h>

// more code

预处理器展开包含后,两个文件都将包含:

int BaseClass::x = 10; 

现在,只要将两个目标文件都传递给链接器,它将看到符号 BaseClass::x 两次 - 这是一个错误。

现在,为了更明显,假设您将其放在头文件中:

int aGlobalVariable = 10;

然后将它包含在两个不同的 cpp 文件中,它们都应该链接到一个可执行文件中。如果从链接器的角度来看,它实际上与您的示例没有任何不同。

为什么类声明没有问题?

声明定义是有区别的。只有后者会引起问题。例如,以下所有内容都是声明:

  • extern int a;
  • void foo(int a);
  • class Foo { int bar(); };

这些是定义:

  • int a;
  • int b = 10;
  • void foo(int a) { /*..*/ }
  • int Foo::bar() { /*...*/ }

只要有一个(并且只有一个)定义,您就可以拥有任意数量的声明,并且链接器将确保它们都引用相同的函数或内存位置。

现在上课呢?只能声明类,而必须定义其成员函数和静态成员。同样,每个定义可能只存在一次。

成员函数和静态成员实际上只在程序的地址空间中存在一次,而普通成员(实例变量)对于类的每个对象都存在。

回到您的具体问题:静态成员基本上只是全局变量,但范围仅限于类的名称。

希望这能为您解决问题!

【讨论】:

  • 但是除了#include "baseClass.h"之外,链接器不也包括类本身的双重定义,这也应该引起问题吗?抱歉,我可能需要一些时间才能理解...
  • 不,因为它只是一个类声明。我会在我的答案中添加一些内容
  • 好的,非常感谢您提供这样一个描述性的答案,我想我开始明白了:)
【解决方案3】:

守卫不会阻止多个源文件中的多个副本。它们只防止在一个源文件中出现多个副本。

如果您有多个#include "base_class.h" 的源文件,您将违反一个定义规则。

【讨论】:

    【解决方案4】:

    因为如果您在标头中对其进行初始化,如果您多次包含标头,则可能会在多个位置定义它。这将导致链接器错误

    【讨论】:

      猜你喜欢
      • 2011-04-19
      • 1970-01-01
      • 1970-01-01
      • 2014-04-13
      • 1970-01-01
      • 2018-06-01
      • 2017-12-07
      • 1970-01-01
      • 2012-02-01
      相关资源
      最近更新 更多