3 回答
TA贡献1780条经验 获得超4个赞
为什么我不能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中实现,因此您可能仍会遇到编译错误。
TA贡献1827条经验 获得超4个赞
这似乎是旧时简单连接器的残留。您可以在静态方法中使用静态变量作为变通方法:
// header.hxx#include <vector>class Class {public: static std::vector<int> & replacement_for_initialized_static_non_const_variable() { static std::vector<int> Static {42, 0, 1900, 1998}; return Static; }};int compilation_unit_a();
和
// compilation_unit_a.cxx#include "header.hxx"int compilation_unit_a() { return Class::replacement_for_initialized_static_non_const_variable()[1]++;}
和
// main.cxx#include "header.hxx"#include <iostream>int main() { std::cout << compilation_unit_a() << Class::replacement_for_initialized_static_non_const_variable()[1]++ << compilation_unit_a() << Class::replacement_for_initialized_static_non_const_variable()[1]++ << std::endl;}
建立:
g++ -std=gnu++0x -save-temps=obj -c compilation_unit_a.cxx g++ -std=gnu++0x -o main main.cxx compilation_unit_a.o
跑:
./main
事实上这一点(一致地,即使类定义包含在不同的编译单元中),也表明今天的链接器(gcc 4.9.2)实际上足够智能。
搞笑:0123
在手臂和3210
x86上打印。
- 3 回答
- 0 关注
- 959 浏览
添加回答
举报