首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >静态数据成员初始化

静态数据成员初始化
EN

Stack Overflow用户
提问于 2012-07-03 04:24:41
回答 7查看 31.7K关注 0票数 22

为什么静态数据成员初始化必须在类之外?

代码语言:javascript
复制
class X
{
public:
      int normalValue = 5; //NSDMI
      static int i;
};

int X::i = 0;

为什么静态数据成员(这里是"i")只是一个声明,而不是一个定义?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2012-07-03 05:16:27

区分初始值设定项和定义是很重要的。修改后的代码是有效的,初始化器在类定义中:

代码语言:javascript
复制
class X
{
public:
  int normalValue = 5;
  static const int i = 0;       // declaration, with initializer
};

const int X::i;                 // definition

也就是说,必须在类之外的是定义,而不是初始化。

这是因为变量必须在内存中有一个地址(除非它只在有限的情况下使用,比如在编译时常量表达式中)。

非静态成员变量存在于它所属的对象中,因此它的地址取决于包含它的对象的地址。每次创建新的X时,也会创建一个新的X::normalValue变量。非静态数据成员的生命周期从类的构造函数开始。NSDMI语法与变量在内存中的地址无关,它只允许您在一个位置提供初始值,而不是在每个具有显式构造函数初始化器列表的构造函数中重复该初始值。

另一方面,静态成员变量不包含在类的实例中,它独立于任何单个实例存在,并且从程序开始就存在于固定地址。为了让静态成员变量(或任何其他全局对象)获得唯一的地址,链接器必须在一个对象文件中恰好看到静态变量的一个定义,并为其分配一个地址。

因为静态变量只需要一个目标文件中的一个定义,所以允许在类中提供该定义是没有意义的,因为类定义通常存在于头文件中,并包含在多个目标文件中。因此,尽管您可以在类中提供初始化器,但您仍然需要在某个地方定义静态数据成员。

您还可以将其视为声明extern变量:

代码语言:javascript
复制
namespace X {
  extern int i;
}

它声明了变量,但程序中的某个地方必须有一个定义:

代码语言:javascript
复制
int X::i = 0;
票数 43
EN

Stack Overflow用户

发布于 2012-07-03 04:43:51

您需要为静态数据成员提供一个单独的定义(如果它使用了odr,如C++11中所定义的那样),因为该定义应该驻留在某个位置--只有一个转换单元。静态类数据成员基本上是类作用域中声明的全局对象(全局变量)。编译器希望您选择一个特定的翻译单元,该翻译单元将保存每个全局对象的实际“主体”。您必须决定将实际对象放在哪个翻译单元中。

票数 7
EN

Stack Overflow用户

发布于 2012-07-03 04:32:58

“静态”类成员就像一个全局分配的变量(它与单个类实例无关),因此它必须驻留在某个目标文件中(并在".cpp“文件中声明),就像任何全局变量一样。

简单类成员(非静态)驻留在为类实例分配的内存块中。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11300652

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档