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

class foo
{
    private:
        static int i;
};

int foo::i = 0;

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


当前回答

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

其他回答

类声明应该在头文件中(如果不共享,则在源文件中)。 文件: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;
};

您遇到的链接器问题可能是由以下原因引起的:

在头文件中提供类和静态成员定义, 在两个或多个源文件中包含此头文件。

对于那些从c++开始学习的人来说,这是一个常见的问题。静态类成员必须在单个翻译单元中初始化,即在单个源文件中初始化。

不幸的是,静态类成员必须在类体之外初始化。这使得只写头的代码变得复杂,因此,我使用了完全不同的方法。你可以通过静态或非静态类函数来提供你的静态对象,例如:

class Foo
{
    // int& getObjectInstance() const {
    static int& getObjectInstance() {
        static int object;
        return object;
    }

    void func() {
        int &object = getValueInstance();
        object += 5;
    }
};

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

#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
int foo::i = 0; 

是初始化变量的正确语法,但它必须放在源文件(.cpp)中,而不是放在头文件中。

因为它是一个静态变量,所以编译器只需要创建它的一个副本。你必须在你的代码中有一行"int foo:i"来告诉编译器把它放在哪里,否则你会得到一个链接错误。如果这是在一个头,你会得到一个拷贝在每个文件,包括头,所以从链接器获得多重定义的符号错误。

这符合你的目的吗?

//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;
}