C++ 为什么必须在定义之外初始化非常量、非int/enum静态数据成员?

C++ 为什么必须在定义之外初始化非常量、非int/enum静态数据成员?,c++,static,header,C++,Static,Header,我知道只有静态、常量和int/enum(c++11之前)的数据成员才能在类声明中初始化。“所有其他静态数据成员必须在全局命名空间范围内定义(即在类定义的主体之外),并且只能在这些定义中初始化” 为什么不能在类定义中初始化其他静态数据成员?这是被禁止的具体原因吗 如果数据成员特定于类,为什么要在全局命名空间范围内声明它们,而不是在与其类相关的某个范围内声明它们 为什么不能在类定义中初始化其他静态数据成员?这是被禁止的具体原因吗 最有可能是因为C++有独立的翻译单位。编译器需要选择一个对象文件,这些

我知道只有静态、常量和int/enum(c++11之前)的数据成员才能在类声明中初始化。“所有其他静态数据成员必须在全局命名空间范围内定义(即在类定义的主体之外),并且只能在这些定义中初始化”

为什么不能在类定义中初始化其他静态数据成员?这是被禁止的具体原因吗

如果数据成员特定于类,为什么要在全局命名空间范围内声明它们,而不是在与其类相关的某个范围内声明它们

为什么不能在类定义中初始化其他静态数据成员?这是被禁止的具体原因吗

最有可能是因为C++有独立的翻译单位。编译器需要选择一个对象文件,这些符号的初始化逻辑将放置在该文件中。强制将其放在特定的源文件中可以使编译器更容易做出决定

如果数据成员特定于类,为什么要在全局命名空间范围内声明它们,而不是在与其类相关的某个范围内声明它们

因为这只是C++如何处理类成员。这与其他类成员(如成员函数)没有区别:

头文件:

namespace example {

// Class declared in header
struct some_class
{
    // Member variable
    static float example;
    // Member function
    void DoStuff() const;
};

}
源文件:

namespace example {

    // Implement member variable
    float some_class::example = 3.14159;
    // Implement member function
    void some_class::DoStuff() const
    {
         //....
    }
}

有一个特殊的异常,允许在头中初始化静态const integral成员,因为它允许编译器将它们视为编译时常量。也就是说,您可以使用它们在类定义中定义数组或其他类似位的大小。

它们将在每次实例化类时重新初始化。每次创建Foo类型的新对象时,所有Foo的静态变量都将重置为其初始值,这可能不是您想要的。因此,如果要在对象中使用静态变量,它们要么a)不能更改其值,这意味着将它们重新初始化为相同的值是安全的,要么b)只能在初始值设定函数的上下文之外更改

为什么不能在类定义中初始化其他静态数据成员?这是被禁止的具体原因吗

通常,所有静态对象都需要在单个转换单元中定义,以便它们具有定义良好的地址。作为一个特殊的例外,如果不需要静态、常量、非易失性类成员的地址,则它们不需要定义,并且它们的类型足够简单,可以用编译时常量替换它们的值

历史上,“足够简单”被定义为整数或枚举类型;C++11将其扩展为包含带有
constexpr
说明符的任何文本类型

如果数据成员特定于类,为什么要在全局命名空间范围内声明它们,而不是在与其类相关的某个范围内声明它们

它们不在全局命名空间范围内声明。它们在类中声明并限定范围

如果你的意思是,为什么它们被定义在类定义之外,那是因为在整个程序中必须只有一个静态成员的定义;但是类必须在使用它的每个翻译单元中定义

为什么不能在类中初始化其他静态数据成员 定义?这是被禁止的具体原因吗

静态数据成员在许多方面(特别是从编译器的角度来看)类似于具有外部链接的命名空间范围数据对象

静态数据成员的声明只是一个声明,而不是一个定义。它类似于全局对象的
extern
声明,必须包含在可能使用该对象的任何翻译单元中

定义必须正好出现在一个翻译单元中,这就是初始值设定项表达式所属的位置。除非表达式满足常量表达式的严格标准,否则它的值很可能取决于调用它的时间和上下文。如果在多个翻译单元中出现这样的初始值设定项表达式,则会使初始化的执行上下文和时间以及最终的初始值变得不明确

类范围的编译时常量被认为具有足够的价值,可以对某些类型的常量静态成员(然后可以用来初始化枚举或指定数组维度等)进行例外。对于常量表达式,在不同的转换单位中意外地产生不同的初始值设定项值至少更难。这个概念在C++11中通过
constexpr
成员进行了扩展

如果数据成员特定于类,为什么要声明它们 在全局命名空间范围中,而不是与其 上课


声明在类范围内。非定义声明实际上在类定义中,定义显示在命名空间范围中,就像类成员的任何其他类外定义一样。成员名由类名限定,因此它清楚地表示为类的成员,并且初始值设定项表达式实际上被视为在类的范围内(至少在C++11中;我这里没有可用的C++98/03标准)。

您必须从另一个角度看它。基本上,静态数据成员必须在类定义之外的源文件中定义和初始化。
static const int
有一个例外,因为它避免了定义成员数组大小的各种难看的解决方法。

“全局命名空间范围”具有误导性——定义发生在实际类的命名空间范围内;不是全局命名空间的作用域。(正如我在回答中所说的)这没有道理。为什么在实例化每个实例时都会初始化静态成员?我想你的最后一段是我第一个问题的答案