在c++中初始化私有静态数据成员的最佳方法是什么?我在头文件中尝试了这一点,但它给了我奇怪的链接器错误:

class foo
{
    private:
        static int i;
};

int foo::i = 0;

我猜这是因为我不能从类外部初始化一个私有成员。那么最好的方法是什么呢?


当前回答

以下是一个简单例子中的所有可能性和错误……

#ifndef Foo_h
#define Foo_h

class Foo
{
  static const int a = 42; // OK
  static const int b {7};  // OK
  //static int x = 42; // ISO C++ forbids in-class initialization of non-const static member 'Foo::x'
  //static int y {7};  // ISO C++ forbids in-class initialization of non-const static member 'Foo::x'
  static int x;
  static int y;
  int m = 42;
  int n {7};
};

// Foo::x = 42;  // error: 'int Foo::x' is private
int Foo::x = 42; // OK in Foo.h if included in only one  *.cpp -> *.o file!
int Foo::y {7};  // OK

// int Foo::y {7};  // error: redefinition of 'int Foo::y'
   // ONLY if the compiler can see both declarations at the same time it, 
   // OTHERWISE you get a linker error

#endif // Foo_h

但最好把它放在Foo.cpp中。这样你就可以单独编译每个文件并在以后链接它们,否则Foo:x将出现在多个目标文件中,并导致链接器错误. ...

// Foo::x = 42;  // error: 'int Foo::x' is private, bad if Foo::X is public!
int Foo::x = 42; // OK in Foo.h if included in only one  *.cpp -> *.o file!
int Foo::y {7};  // OK

其他回答

我在这里没有足够的代表来添加这一点作为注释,但在我看来,无论如何使用#include守卫来编写头文件是一种很好的风格,正如Paranaix几小时前指出的那样,这可以防止多重定义错误。除非已经使用了单独的CPP文件,否则没有必要只使用一个文件来初始化静态的非整型成员。

#ifndef FOO_H
#define FOO_H
#include "bar.h"

class foo
{
private:
    static bar i;
};

bar foo::i = VALUE;
#endif

我认为没有必要为此使用单独的CPP文件。当然,你可以这样做,但是没有技术上的理由必须这样做。

set_default()方法怎么样?

class foo
{
    public:
        static void set_default(int);
    private:
        static int i;
};

void foo::set_default(int x) {
    i = x;
}

我们只需要使用set_default(int x)方法,我们的静态变量就会被初始化。

这与其他注释并不矛盾,实际上它遵循了在全局作用域中初始化变量的相同原则,但是通过使用这个方法,我们使其显式(并且易于看到-理解),而不是将变量的定义挂在那里。

也在privatstatic .cpp文件中工作:

#include <iostream>

using namespace std;

class A
{
private:
  static int v;
};

int A::v = 10; // possible initializing

int main()
{
A a;
//cout << A::v << endl; // no access because of private scope
return 0;
}

// g++ privateStatic.cpp -o privateStatic && ./privateStatic

我遵循卡尔的想法。我喜欢它,现在我也在用它。 我稍微改变了一下符号,增加了一些功能

#include <stdio.h>

class Foo
{
   public:

     int   GetMyStaticValue () const {  return MyStatic();  }
     int & GetMyStaticVar ()         {  return MyStatic();  }
     static bool isMyStatic (int & num) {  return & num == & MyStatic(); }

   private:

      static int & MyStatic ()
      {
         static int mStatic = 7;
         return mStatic;
      }
};

int main (int, char **)
{
   Foo obj;

   printf ("mystatic value %d\n", obj.GetMyStaticValue());
   obj.GetMyStaticVar () = 3;
   printf ("mystatic value %d\n", obj.GetMyStaticValue());

   int valMyS = obj.GetMyStaticVar ();
   int & iPtr1 = obj.GetMyStaticVar ();
   int & iPtr2 = valMyS;

   printf ("is my static %d %d\n", Foo::isMyStatic(iPtr1), Foo::isMyStatic(iPtr2));
}

这个输出

mystatic value 7
mystatic value 3
is my static 1 0

我只是想提一下我第一次遇到这个的时候觉得有点奇怪的东西。

我需要在模板类中初始化一个私有静态数据成员。

在.h或.hpp中,它看起来像这样初始化模板类的静态数据成员:

template<typename T>
Type ClassName<T>::dataMemberName = initialValue;