为什么静态数据成员初始化必须在类之外?
class X
{
public:
int normalValue = 5; //NSDMI
static int i;
};
int X::i = 0;
为什么静态数据成员(此处为“i”)只是一个声明,而不是一个定义?
答案 0 :(得分:36)
区分初始值设定项非常重要,初始化值表示其初始值是什么,以及定义。这个修改过的代码是有效的,初始化器在类定义中:
class X
{
public:
int normalValue = 5;
static const int i = 0; // declaration, with initializer
};
const int X::i; // definition
即。在课外必须是定义,而不是初始化。
那是因为变量必须在内存中有一个地址(除非它仅在有限的情况下使用,例如在编译时常量表达式中。)
非静态成员变量存在于它所属的对象内部,因此其地址取决于包含它的对象的地址。每次创建新X
时,您还会创建一个新的X::normalValue
变量。非静态数据成员的生命周期从类的构造函数开始。 NSDMI语法与内存中的变量地址没有任何关系,它只允许您在一个地方提供初始值,而不是在每个构造函数中使用显式构造函数初始化列表重复它。
另一方面,静态成员变量不包含在类的实例中,它独立于任何单个实例而存在,并且从程序的开头就存在于固定地址。为了使静态成员变量(或任何其他全局对象)获得唯一的地址,链接器必须只在一个目标文件中看到静态变量的一个定义,并为其分配一个地址。
因为静态变量只需要在一个目标文件中只有一个定义,所以允许在类中提供该定义是没有意义的,因为类定义通常存在于头文件中并包含在多个目标文件中。因此,尽管您可以在类中提供初始化程序,但仍需要在某处定义静态数据成员。
您也可以将其视为声明extern
变量:
namespace X {
extern int i;
}
这声明了变量,但程序中必须有一个定义:
int X::i = 0;
答案 1 :(得分:7)
您需要为静态数据成员提供单独的定义(如果其 odr-used ,如C ++ 11中所定义),因为该定义应位于某个地方 - 只有一个翻译单位。静态类数据成员基本上是类范围中声明的全局对象(全局变量)。编译器希望您选择一个特定的转换单元来保存每个全局对象的实际“主体”。您必须决定将实际对象放在哪个翻译单元。
答案 2 :(得分:3)
“static”类成员类似于全局分配的变量(它与单个类实例无关),因此它必须驻留在某个目标文件中(并在“.cpp”文件中声明)作为符号就像任何全局变量一样。
简单类成员(非静态)驻留在为类实例分配的内存块中。
答案 3 :(得分:2)
原因很简单,因为类通常在 header 文件中声明,这些文件通常包含在多个cpp文件中。静态数据成员具有外部链接,并且必须在一个翻译单元中声明,这使得它们不适合在类中定义。
正如juanchopanza指出允许以下内容:
struct A
{
const static int i = 1;
};
但是,这只是声明而不是定义。如果要在某处使用i
的地址,您仍需要定义它。
例如:
f(int);
g(int&);
X<A::i> x; // Okay without definition for template arguments
char a[A::i]; // Okay without definition, just using value as constant expression
&A::i; // Need a definition because I'm taking the address
f(A::i); // Okay without definition for pass by value
g(A::i); // Need a definition with pass by reference
答案 4 :(得分:1)
当编译器从一个单元生成二进制代码时(极端简化:一个cpp文件及其所有包含的头文件),它将为静态变量发出一个符号,并最终为该变量初始化代码。
可以在多个单元中声明静态变量符号,但不能多次初始化它。
因此,您必须确保仅为单个单元发出初始化代码。 这意味着静态变量必须只用一个单位定义。
答案 5 :(得分:1)
请记住,如果它是const枚举类型的const整数类型,则可以在声明点初始化静态数据成员:
来自C ++ 03标准,§9.4.2
如果静态数据成员是const integral或const枚举类型,则在类中声明它 definition可以指定一个常量初始化器,它应该是一个整型常量表达式(5.19)
struct Foo {
static const int j = 42; // OK
};
答案 6 :(得分:0)
静态数据成员
#include<iostream.h>
#include<conio.h>
class static_var
{
static int count; //static member of class
public :
void incr_staticvar()
{
count++;
}
void outputc()
{
cout<<"Value of Static variable Count :- "<<count<<endl;
}
};
int static_var::count;
void main()
{
clrscr();
static_var obj1,obj2,obj3,obj4;
obj1.incr_staticvar();
obj2.incr_staticvar();
obj3.incr_staticvar();
obj4.incr_staticvar();
cout<<"\nAfter Increment of static variable by Four Different objects is :-\n";
obj1.outputc ( );
obj2.outputc ( );
obj3.outputc ( );
obj4.outputc ( );
getch();
}