为什么必须在C ++中定义静态数据成员?

时间:2019-08-07 05:24:37

标签: c++

我总是很难发现为什么我的代码中会出现“对静态变量的未定义引用”,而我总是会遇到以下问题:

Undefined reference to static variable c++

Undefined reference to static variable

我知道我需要在类声明之外定义数据。

在示例中:

class Helloworld {
  public:
     static int x;
     void foo();
};

int Helloworld::x = 0; // Or whatever is the most appropriate value
                       // for initializing x. Notice, that the
                       // initializer is not required: if absent,
                       // x will be zero-initialized.

我必须将x初始化为某个值。但是作为类实例的静态成员呢? 为什么简单地编译器不会使用默认构造函数为我创建实例?

如果我写

class A {
    public: 
        B b;
}

那我就可以做

A a;
a.b;

我不需要在B b类声明之外定义A。为什么在下面的静态示例中需要这样做?

class A {
    public: 
        static B b;
}

B A::b

3 个答案:

答案 0 :(得分:4)

静态成员在创建任何对象之前就已经存在,这使它们成为静态。因此,它们的初始化不会在一开始就发生,而是已经存在。

它们实际上是类范围内的全局变量。

也就是说,您可以使用inline修饰符在类内对其进行初始化,而无需进行类外声明。

信息herehere

答案 1 :(得分:4)

  

但是作为类实例的静态成员呢?为什么简单地编译器不会使用默认构造函数为我创建实例?

但要放在哪里?在C ++ 17之前进行此操作的合理性是,在一个定义规则下,必须只有一个这样的静态成员定义。因此,即使对象要进行默认的初始化,也要由程序员确切地定义该定义应驻留在哪个翻译单元中。不信任编译器“做正确的事” TM

随着编译器变得越来越聪明,以及C ++ 17的出现,事实证明编译器确实可以解决这个问题。在C ++ 17中,您可以将静态成员指定为内联变量,编译器/链接器会对其进行整理。

class A {
    public: 
        static inline B b; // There, an inline variable default initialized.
};

答案 2 :(得分:0)

您需要在类外定义B,其原因与在类外定义x的原因相同:因为它是静态成员。是原始类型(int)或类类型(B)与它无关!