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

class foo
{
    private:
        static int i;
};

int foo::i = 0;

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


当前回答

从c++ 17开始,静态成员可以在头文件中用inline关键字定义。

http://en.cppreference.com/w/cpp/language/static

静态数据成员可以内联声明。内联静态数据成员可以在类定义中定义,并且可以指定默认成员初始化式。它不需要一个类外定义:

struct X
{
    inline static int n = 1;
};

其他回答

类声明应该在头文件中(如果不共享,则在源文件中)。 文件:foo。

class foo
{
    private:
        static int i;
};

但是初始化应该在源文件中。 文件:foo.cpp

int foo::i = 0;

如果初始化是在头文件中,那么每个包含头文件的文件都有一个静态成员的定义。因此,在链接阶段,你会得到链接器错误,因为初始化变量的代码将在多个源文件中定义。 静态int i的初始化必须在任何函数之外完成。

注意:Matt Curtis:指出,如果静态成员变量是const整数类型(bool, char, char8_t[自c++ 20以来],char16_t, char32_t, wchar_t, short, int, long, long long,或任何实现定义的扩展整数类型,包括任何有符号,无符号和cv限定变量),c++允许简化上述内容。然后你可以直接在头文件的类声明中声明和初始化成员变量:

class foo
{
    private:
        static int const i = 42;
};

对于变量:

foo。:

class foo
{
private:
    static int i;
};

foo.cpp:

int foo::i = 0;

这是因为在你的程序中只能有一个foo::i实例。它相当于头文件中的extern int i和源文件中的int i。

对于常量,你可以把值直接放在类声明中:

class foo
{
private:
    static int i;
    const static int a = 42;
};

如果你想初始化一些复合类型(f.e. string),你可以这样做:

class SomeClass {
  static std::list<string> _list;

  public:
    static const std::list<string>& getList() {
      struct Initializer {
         Initializer() {
           // Here you may want to put mutex
           _list.push_back("FIRST");
           _list.push_back("SECOND");
           ....
         }
      }
      static Initializer ListInitializationGuard;
      return _list;
    }
};

由于ListInitializationGuard是SomeClass::getList()方法中的一个静态变量,它将只被构造一次,这意味着构造函数被调用一次。这将初始化_list变量为你需要的值。任何后续对getList的调用都将返回已经初始化的_list对象。

当然,您必须始终通过调用getList()方法访问_list对象。

也在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

定义常量的一种“老派”方法是用枚举替换它们:

class foo
{
    private:
        enum {i = 0}; // default type = int
        enum: int64_t {HUGE = 1000000000000}; // may specify another type
};

这种方法不需要提供定义,并且避免使常量为左值,这可以为您省去一些麻烦,例如当您意外地odr使用它时。