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

class foo
{
    private:
        static int i;
};

int foo::i = 0;

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


当前回答

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

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

class foo
{
private:
    static bar i;
};

bar foo::i = VALUE;
#endif

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

其他回答

这符合你的目的吗?

//header file

struct MyStruct {
public:
    const std::unordered_map<std::string, uint32_t> str_to_int{
        { "a", 1 },
        { "b", 2 },
        ...
        { "z", 26 }
    };
    const std::unordered_map<int , std::string> int_to_str{
        { 1, "a" },
        { 2, "b" },
        ...
        { 26, "z" }
    };
    std::string some_string = "justanotherstring";  
    uint32_t some_int = 42;

    static MyStruct & Singleton() {
        static MyStruct instance;
        return instance;
    }
private:
    MyStruct() {};
};

//Usage in cpp file
int main(){
    std::cout<<MyStruct::Singleton().some_string<<std::endl;
    std::cout<<MyStruct::Singleton().some_int<<std::endl;
    return 0;
}

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

#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

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

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

class foo
{
private:
    static bar i;
};

bar foo::i = VALUE;
#endif

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

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

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

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

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

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