为什么非const、非int/enum静态数据成员必须在定义之外初始化?
Why do non-const, non-int/enum static data members have to be initialized outside the definition?
我理解只有静态,const和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整型成员,因为它允许编译器将它们视为编译时常量。也就是说,您可以在类定义中使用它们来定义数组或其他类似位的大小。
为什么不能在类定义中初始化其他静态数据成员?这是被禁止的具体原因吗?
一般来说,所有的静态对象都需要一个定义,在一个单独的转换单元中,这样它们就有一个定义良好的地址。作为一个特殊的例外,静态、常量、非易失性类成员不需要定义,如果不需要它们的地址,并且它们具有足够简单的类型,可以用编译时常量替换它们的值。
过去,"足够简单"被定义为整型或枚举类型;c++ 11将其扩展为包含任何具有constexpr
说明符的文字类型。
如果数据成员是特定于类的,为什么要在全局命名空间作用域声明它们,而不是在与其类相关的作用域声明它们?
它们不在全局命名空间范围内声明。它们被声明并限定在类内。
如果你的意思是,为什么它们在类定义之外定义,那是因为在整个程序中静态成员必须只有一个定义;但是该类必须在使用它的每个翻译单元中定义。为什么不能在类中初始化其他静态数据成员定义呢?这是被禁止的具体原因吗?
静态数据成员在许多方面(特别是从编译器的角度来看)类似于具有外部链接的名称空间范围的数据对象。
静态数据成员的声明只是一个声明,而不是定义。它类似于全局对象的extern
声明,必须包含在可能使用该对象的任何翻译单元中。
定义必须恰好出现在一个翻译单元中,这就是初始化表达式所在的位置。除非表达式满足常量表达式的严格标准,否则它的值很可能取决于调用它的时间和上下文。如果这样的初始化表达式出现在多个翻译单元中,将使初始化的执行上下文和时间以及最终的初始值变得不明确。
类作用域的编译时常量被认为足够有价值,可以对某些类型的常量静态成员(然后可用于初始化枚举或指定数组维数等)发出异常。对于常量表达式,在不同的翻译单元中意外产生不同的初始化项值至少会更困难。这个概念在c++ 11中扩展为constexpr
成员。
如果数据成员是特定于类的,为什么要声明它们全局命名空间作用域,而不是与其相关的作用域课吗?
声明在类范围内。非定义声明实际上在类定义中,定义出现在名称空间作用域中,就像类成员的任何其他类外定义一样。成员名由类名限定,因此它被清楚地表示为类的成员,并且初始化表达式实际上被认为在类的作用域内(至少在c++ 11;我这里没有c++ 98/03标准可用)。
你必须从另一个角度来看。基本上,静态数据成员必须在类定义之外的源文件中定义和初始化。static const int
有一个例外,因为它避免了定义成员数组大小的各种难看的变通方法。
它们将在每次实例化类时重新初始化。每次创建Foo类型的新对象时,所有Foo的静态变量都将重置为其初始值,这可能不是您想要的。因此,如果你想在对象中使用静态变量,它们要么a)不能改变它们的值,这意味着将它们重新初始化为相同的值是安全的,要么b)只能在初始化函数的上下文中进行更改。
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- Boost Python Numpy - 要初始化的未定义引用
- 虚拟成员函数的定义是否强制在同一转换单元中动态初始化静态数据成员?
- C++类中的类作为自定义向量(如何初始化?
- 初始化类定义中的结构数组
- C++ 如何检查 char 变量是否未定义(未初始化)
- C++列表初始化允许多个用户定义的转换
- (2 问题)"类"类型重新定义(即使 #pragma 一次),以及静态函数内的静态成员对象初始化?
- (C++)我的自定义数组无法初始化(编译错误)
- 类模板静态数据成员定义/声明/初始化
- 初始化在类类型 #define 中定义的非静态成员数组,不带默认 ctor
- 在另一个文件中初始化的 extern 数组中未定义的引用
- thread_local静态成员模板定义:初始化失败,GCC
- 通过用户定义的转换初始化引用
- 自定义初始化数组与 std::make_unique
- C++具有自定义初始化的静态调度
- 导入错误:动态模块未定义初始化函数
- 有没有一种标准的方法可以在初始化阶段运行一些代码并定义初始化的顺序
- C++,为什么我不能把带有参数的类构造函数的定义-初始化列表放在类声明之外
- 是否需要在头文件中定义初始化列表