在C ++中定义静态成员

时间:2010-08-21 04:49:40

标签: c++ static

我试图像这样定义一个公共静态变量:

public :
         static int j=0;        //or any other value too

我在这一行上遇到了编译错误:ISO C ++禁止非const静态成员`j'的类内初始化。

  1. 为什么在C ++中不允许这样做?

  2. 为什么允许const成员初始化?

  3. 这是否意味着C ++中的静态变量未在C中初始化为0?

  4. 谢谢!

6 个答案:

答案 0 :(得分:20)

您必须在.cpp文件中初始化静态变量,而不是在类声明中。

在类中声明静态变量时,可以在不实例化类的情况下使用它。

//Header file
class Test
{
  public:
    static int j;
};

//In cpp file

//Initialize static variables here.
int Test::j = 0;

//Constructor
Test::Test(void)
{
   //Class initialize code
}

答案 1 :(得分:18)

  

为什么在C ++中不允许这样做?

除非您定义它,否则该变量不会成为l值。

  

为什么允许const成员初始化?

即使在这种情况下,如果要获取变量的地址,也需要定义。

  

9.4.2静态数据成员

     

2 声明静态数据   其类定义中的成员不是   一个定义,可能是一个   不完整的类型   cv合格的空白。的定义   静态数据成员应出现在   包含成员的命名空间范围   类定义。在定义中   命名空间范围,名称   静态数据成员应具备资格   通过其类名使用::   运营商。初始化表达式   在静态数据的定义中   成员属于其类的范围

此外,这主要是一个使用工件,因此您可以编写:

class S {
      static const int size = 42;
      float array[ size ];
};
  

这是否意味着C ++中的静态变量未使用0初始化   在C?

不,他们是:

  

3.6.2非局部变量的初始化

     

具有静态存储持续时间的变量   (3.7.1)或线程存储持续时间   (3.7.2)应为零初始化(8.5)   在任何其他初始化之前   的地方。

尽管在C ++ 0x中事情变得更加棘手。现在可以初始化所有文字类型(而不是当前标准中只有整数类型),这意味着现在可以使用声明中的初始化程序初始化所有标量类型(包括浮点数)和某些类类型。

答案 2 :(得分:18)

  

(1。)为什么在C ++中不允许这样做?

来自Bjarne Stroustrup's C++ Style and Technique FAQA class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.

  

(2。)为什么允许const成员   被初始化?

[dirkgently said it better]

  

(3。)这是否意味着静态变量   在C ++中没有用0初始化   在C?

据我所知,只要你在.cpp中声明静态成员var,如果没有另外指定,它将被零初始化:

// in some .cpp
int Test::j; // j = int();

答案 3 :(得分:8)

答案简短:

这相当于说extern int Test_j = 0;

如果确实编译了,会发生什么?包含类的头文件的每个源文件都会定义一个名为Test :: j的符号,该符号初始化为0.链接器往往不喜欢它。

答案 4 :(得分:2)

class GetData        
{    
private:     
static int integer;   //Static variable must be defined with the extension of keyword static;      
public:      
static void enter(int x)      
{       
integer = x;  //static variable passed through the static function    
}
static int  show()   //declared and defined
{
    return integer;   //will return the integer's value
}        
};        
int GetData::integer = 0;    //Definition of the static variable       
int main()      
{      
   GetData::enter(234);    //value has been passed through the static function enter. Note that class containing static variables may not have the object in main. They can be called by scope resolution operator in main.
   cout<<GetData::show();      
}     

答案 5 :(得分:0)

问题更多的是为什么您必须在类 staticconst 中明确定义一个 inline 成员,而您不必为 {{ 1}} 方法,在类中定义时自动生成 static。更广泛地说,问题是为什么在类中定义方法使其成为 inline 以及为什么不能在类中定义静态成员被视为 inline 或文件范围类范围全局符号就像一个外部定义,而不是使它成为编译器错误。

当您定义它 inline 时,它将优化负载,如果您通过使其 static const 或获取它的地址来强制它加载值,您将收到链接器错误,因为它从不发出符号(clang 会强迫你定义一个不合时宜的 volatile const,但 gcc 不会)。这与文件范围内的 static volatile const 非常不同。

这对我说的是 const 成员的默认设置是根本不发出符号,而不是 staticinline 允许将值作为立即数优化到代码中(这就是为什么它实际上允许您将其定义为 const,因为如果您不这样做,那么您将没有符号并且然后引用那个丢失的符号)但编译器仍然不发出符号。但这是为什么呢?为什么不让它像方法一样默认为 const,而不是根本不发出任何符号?

它与方法的唯一区别是相同的定义可以有多个不同的值——如果你defined the class type in an anonymous namespace it would have static (local) linkage,那么你可以避免重新定义错误。现在,如果将其包含在翻译单元中,它将在不同的翻译单元中具有多个不同的状态,但方法不会(它将具有多个定义,但这些定义将是相同的)。非静态链接也是如此,如果方法是inline,会任意选择其中一个定义,否则会出现多重定义错误。使用 inline 链接,它仍然阻止您在没有 static 的类中定义 static 成员,因为它仍然不会发出符号。

因为它阻止您定义成员(即不发出符号)何时(静态链接)和不会(外部链接因此链接器错误)具有多个值状态,以及何时会出现链接器错误(外部链接),当没有链接器错误(静态链接)时,这与这些属性无关。

所以你要问为什么在类中定义的成员的意图是不合时宜的(即像一个常规的文件范围符号),而在类中定义的方法的意图是{{1} } (即仅在翻译单元中使用时才发出符号,以及select only one symbol in the comdat group to use)。我的意思是,当程序员在一个类中定义一个静态方法时,它被假定为相同的方法,但是当他们定义一个成员时,它可能有许多不同的值,这是 comdat 链接的问题,因为你不知道它将选择哪个符号,并且将是一个无声的逻辑错误:

inline
inline

如果它强迫你定义它,你会得到一个链接器重定义错误,从而更容易诊断。诚然,如果方法定义不同,也会出现同样的问题,这里的整个假设是类定义应该在头文件中——那么为什么定义会有所不同。

如果将类中的静态成员定义包含在多个文件中,则使类中的静态成员定义表现得像外联定义会导致链接器错误,因此默认情况下不会将其解释为外联定义,因为烦恼。但是,我看不出有什么理由不隐式 // file.cpp #include <iostream> struct c { static inline int k = 3; }; int func(){ std::cout << c::k; return 0; } 像类中定义的静态方法那样。

我认为除了“事情就是这样”之外,没有其他答案。这有点像为什么您不能使用 // main.cpp #include <iostream> struct c { static inline int k = 4; }; int main() { std::cout << c::k; // prints 3 } 来提供方法静态链接(这是一个错误,或者 inlinestatic 上被完全忽略)但您可以将其包含在一个匿名命名空间来实现这一点(并且匿名命名空间必须围绕定义和声明(因此是类),而不仅仅是定义(或不​​仅仅是声明——但这无论如何都是不可能的,因为如果声明在匿名命名空间中)那么定义必须是,否则它不会编译))。到目前为止,我还没有在 SO 上看到任何这样的答案。