为什么我不能在类中初始化非const静态成员或静态数组?

为什么我不能在类中初始化非const静态成员或静态数组?

为什么我不能在类中初始化非const static成员或static数组?

class A{
    static const int a = 3;
    static int b = 3;
    static const int c[2] = { 1, 2 };
    static int d[2] = { 1, 2 };};int main(){
    A a;

    return 0;}

编译器发出以下错误:

g++ main.cpp
main.cpp:4:17: error: ISO C++ forbids in-class initialization of non-const static member ‘b’main.cpp:5:26: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:5:33: error: invalid in-class initialization of static data member of non-integral type ‘const int [2]’main.cpp:6:20: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:6:27: error: invalid in-class initialization of static data member of non-integral type ‘int [2]’

我有两个问题:

  1. 为什么我不能static在课堂上初始化数据成员?

  2. 为什么我不能static在类中初始化数组,甚至是const数组?


猛跑小猪
浏览 960回答 3
3回答

Helenr

为什么我不能static在课堂上初始化数据成员?C ++标准只允许在类中初始化静态常量积分或枚举类型。这是a允许初始化而其他人没有的原因。参考:C ++ 03 9.4.2静态数据成员§4如果静态数据成员是const integer或const枚举类型,则它在类定义中的声明可以指定一个常量初始化器,它应该是一个整型常量表达式(5.19)。在这种情况下,成员可以出现在整数常量表达式中。如果在程序中使用该成员,并且名称空间范围定义不包含初始化程序,则该成员仍应在名称空间作用域中定义。什么是整体类型?C ++ 03 3.9.1基本类型§7类型bool,char,wchar_t以及有符号和无符号整数类型统称为整数类型.43)整数类型的同义词是整数类型。脚注:43)因此,列举(7.2)不是不可或缺的; 但是,枚举可以提升为int,unsigned int,long或unsigned long,如4.5中所述。解决方法:您可以使用枚举技巧初始化类定义中的数组。class A  {     static const int a = 3;     enum { arrsize = 2 };     static const int c[arrsize] = { 1, 2 };};为什么标准不允许这样做?Bjarne 在这里恰当地解释了这一点:类通常在头文件中声明,并且头文件通常包含在许多翻译单元中。但是,为避免复杂的链接器规则,C ++要求每个对象都有唯一的定义。如果C ++允许将需要作为对象存储在内存中的实体的类内定义,则该规则将被破坏。为什么只static const允许整数类型和枚举进行类内初始化?答案隐藏在Bjarne的引言中,仔细阅读,“C ++要求每个对象都有一个唯一的定义。如果C ++允许将需要作为对象存储在内存中的实体的类内定义,那么该规则就会被破坏。”请注意,只有static const整数可以被视为编译时常量。编译器知道整数值不会随时改变,因此它可以应用自己的魔法并应用优化,编译器只是内联这样的类成员,即它们不再存储在内存中,因为需要存储在内存中被删除,它给这些变量提供了Bjarne提到的规则的例外。值得注意的是,即使static const整数值可以具有类内初始化,也不允许采用这些变量的地址。如果(并且仅当)它具有类外定义,则可以获取静态成员的地址。这进一步验证了上面的推理。允许枚举这是因为枚举类型的值可以在期望int的位置使用。看上面的引文这在C ++ 11中是如何变化的?C ++ 11在一定程度上放宽了限制。C ++ 11 9.4.2静态数据成员§3如果静态数据成员是const文字类型,则其在类定义中的声明可以指定一个大括号或大小为初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式。可以在类定义中使用if 声明文字类型的静态数据成员,其声明应指定一个大括号或者等于初始化器,其中每个initializer子句都是赋值表达式constexpr specifier;是一个不变的表达。[注意:在这两种情况下,成员可能会出现在常量表达式中。-end note]如果在程序中使用该成员,并且命名空间作用域定义不包含初始化程序,则该成员仍应在命名空间作用域中定义。此外,C ++ 11 将允许(§12.6.2.8)在声明它(在其类中)的地方初始化非静态数据成员。这将意味着很容易的用户语义。请注意,这些功能尚未在最新的gcc 4.7中实现,因此您可能仍会遇到编译错误。

GCT1015

这似乎是旧时简单连接器的残留。您可以在静态方法中使用静态变量作为变通方法://&nbsp;header.hxx#include&nbsp;<vector>class&nbsp;Class&nbsp;{public: &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;std::vector<int>&nbsp;&&nbsp;replacement_for_initialized_static_non_const_variable()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;std::vector<int>&nbsp;Static&nbsp;{42,&nbsp;0,&nbsp;1900,&nbsp;1998}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Static; &nbsp;&nbsp;&nbsp;&nbsp;}};int&nbsp;compilation_unit_a();和//&nbsp;compilation_unit_a.cxx#include&nbsp;"header.hxx"int&nbsp;compilation_unit_a()&nbsp;{&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Class::replacement_for_initialized_static_non_const_variable()[1]++;}和//&nbsp;main.cxx#include&nbsp;"header.hxx"#include&nbsp;<iostream>int&nbsp;main()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&nbsp;&nbsp;&nbsp;<<&nbsp;compilation_unit_a() &nbsp;&nbsp;&nbsp;&nbsp;<<&nbsp;Class::replacement_for_initialized_static_non_const_variable()[1]++ &nbsp;&nbsp;&nbsp;&nbsp;<<&nbsp;compilation_unit_a() &nbsp;&nbsp;&nbsp;&nbsp;<<&nbsp;Class::replacement_for_initialized_static_non_const_variable()[1]++ &nbsp;&nbsp;&nbsp;&nbsp;<<&nbsp;std::endl;}建立:g++&nbsp;-std=gnu++0x&nbsp;-save-temps=obj&nbsp;-c&nbsp;compilation_unit_a.cxx&nbsp; g++&nbsp;-std=gnu++0x&nbsp;-o&nbsp;main&nbsp;main.cxx&nbsp;compilation_unit_a.o跑:./main事实上这一点(一致地,即使类定义包含在不同的编译单元中),也表明今天的链接器(gcc 4.9.2)实际上足够智能。搞笑:0123在手臂和3210x86上打印。

精慕HU

我认为这是为了防止你混淆声明和定义。(想想如果将文件包含在多个位置可能会出现的问题。)
打开App,查看更多内容
随时随地看视频慕课网APP