如何在 C++ 中初始化私有静态成员?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/185844/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:32:47  来源:igfitidea点击:

How to initialize private static members in C++?

c++initializationstatic-members

提问by Jason Baker

What is the best way to initialize a private, static data member in C++? I tried this in my header file, but it gives me weird linker errors:

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

class foo
{
    private:
        static int i;
};

int foo::i = 0;

I'm guessing this is because I can't initialize a private member from outside the class. So what's the best way to do this?

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

回答by Martin York

The class declaration should be in the header file (Or in the source file if not shared).
File: foo.h

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

class foo
{
    private:
        static int i;
};

But the initialization should be in source file.
File: foo.cpp

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

int foo::i = 0;

If the initialization is in the header file then each file that includes the header file will have a definition of the static member. Thus during the link phase you will get linker errors as the code to initialize the variable will be defined in multiple source files. The initialisation of the static int imust be done outside of any function.

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

Note:Matt Curtis: points out that C++ allows the simplification of the above if the static member variable is of const int type (e.g. int, bool, char). You can then declare and initialize the member variable directly inside the class declaration in the header file:

注意:Matt Curtis:指出如果静态成员变量是 const int 类型(例如int, bool, char),C++ 允许上述简化。然后可以直接在头文件的类声明中声明和初始化成员变量:

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

回答by Matt Curtis

For a variable:

对于变量

foo.h:

foo.h:

class foo
{
private:
    static int i;
};

foo.cpp:

foo.cpp:

int foo::i = 0;

This is because there can only be one instance of foo::iin your program. It's sort of the equivalent of extern int iin a header file and int iin a source file.

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

For a constantyou can put the value straight in the class declaration:

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

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

回答by Die in Sente

Since C++17, static members may be defined in the header with the inlinekeyword.

从 C++17 开始,可以使用inline关键字在标头中定义静态成员。

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

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

"A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify a default member initializer. It does not need an out-of-class definition:"

“可以内联声明静态数据成员。可以在类定义中定义内联静态数据成员,并且可以指定默认成员初始值设定项。它不需要类外定义:”

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

回答by Joshua Clayton

For future viewers of this question, I want to point out that you should avoid what monkey0506 is suggesting.

对于这个问题的未来观众,我想指出你应该避免monkey0506所暗示的

Header files are for declarations.

头文件用于声明。

Header files get compiled once for every .cppfile that directly or indirectly #includesthem, and code outside of any function is run at program initialization, before main().

头文件为每个.cpp直接或间接#includes它们的文件编译一次,并且任何函数之外的代码在程序初始化时运行,在main().

By putting: foo::i = VALUE;into the header, foo:iwill be assigned the value VALUE(whatever that is) for every .cppfile, and these assignments will happen in an indeterminate order (determined by the linker) before main()is run.

通过将:foo::i = VALUE;放入标题中,foo:i将为VALUE每个.cpp文件分配值(无论是什么),并且这些分配将在main()运行之前以不确定的顺序(由链接器确定)发生。

What if we #define VALUEto be a different number in one of our .cppfiles? It will compile fine and we will have no way of knowing which one wins until we run the program.

如果我们#define VALUE在我们的一个.cpp文件中使用不同的数字怎么办?它会编译得很好,在我们运行程序之前,我们无法知道哪一个获胜。

Never put executed code into a header for the same reason that you never #includea .cppfile.

切勿将执行代码放到一个头部出于同样的原因,你从来没有#include一个.cpp文件。

include guards (which I agree you should always use) protect you from something different: the same header being indirectly #included multiple times while compiling a single .cppfile

包含守卫(我同意你应该总是使用它)保护你免受不同的东西:#include在编译单个.cpp文件时,同一个标头被间接d 多次

回答by Johann Gerell

With a Microsoft compiler[1], static variables that are not int-like can also be defined in a header file, but outside of the class declaration, using the Microsoft specific __declspec(selectany).

使用 Microsoft 编译器 [1],int也可以在头文件中定义非-like 的静态变量,但在类声明之外,使用 Microsoft 特定的__declspec(selectany).

class A
{
    static B b;
}

__declspec(selectany) A::b;

Note that I'm not saying this is good, I just say it can be done.

请注意,我并不是说这很好,我只是说它可以做到。

[1] These days, more compilers than MSC support __declspec(selectany)- at least gcc and clang. Maybe even more.

[1] 这些天来,编译器比 MSC 支持的要多__declspec(selectany)——至少是 gcc 和 clang。也许更多。

回答by David Dibben

int foo::i = 0; 

Is the correct syntax for initializing the variable, but it must go in the source file (.cpp) rather than in the header.

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

Because it is a static variable the compiler needs to create only one copy of it. You have to have a line "int foo:i" some where in your code to tell the compiler where to put it otherwise you get a link error. If that is in a header you will get a copy in every file that includes the header, so get multiply defined symbol errors from the linker.

因为它是一个静态变量,编译器只需要创建它的一个副本。您必须在代码中的某处使用一行“int foo:i”来告诉编译器将它放在哪里,否则会出现链接错误。如果它在标题中,您将在包含标题的每个文件中获得一个副本,因此从链接器获得多重定义的符号错误。

回答by monkey0506

I don't have enough rep here to add this as a comment, but IMO it's good style to write your headers with #include guardsanyway, which as noted by Paranaix a few hours ago would prevent a multiple-definition error. Unless you're already using a separate CPP file, it's not necessary to use one just to initialize static non-integral members.

我在这里没有足够的代表将其添加为评论,但 IMO无论如何使用#include 保护编写标题是一种很好的风格,正如 Paranaix 几个小时前指出的那样,这将防止多定义错误。除非您已经在使用单独的 CPP 文件,否则没有必要仅使用一个来初始化静态非整数成员。

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

class foo
{
private:
    static bar i;
};

bar foo::i = VALUE;
#endif

I see no need to use a separate CPP file for this. Sure, you can, but there's no technical reason why you should have to.

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

回答by Kris Kwiatkowski

If you want to initialize some compound type (f.e. string) you can do something like that:

如果你想初始化一些复合类型(fe 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;
    }
};

As the ListInitializationGuardis a static variable inside SomeClass::getList()method it will be constructed only once, which means that constructor is called once. This will initialize _listvariable to value you need. Any subsequent call to getListwill simply return already initialized _listobject.

由于ListInitializationGuardSomeClass::getList()方法内部的静态变量,它只会被构造一次,这意味着构造函数被调用一次。这将initialize _list根据您需要的值而变化。任何后续调用都getList将简单地返回已初始化的_list对象。

Of course you have to access _listobject always by calling getList()method.

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

回答by Kris Kwiatkowski

You can also include the assignment in the header file if you use header guards. I have used this technique for a C++ library I have created. Another way to achieve the same result is to use static methods. For example...

如果您使用头文件保护,您还可以在头文件中包含分配。我已将此技术用于我创建的 C++ 库。实现相同结果的另一种方法是使用静态方法。例如...

class Foo
   {
   public:
     int GetMyStatic() const
     {
       return *MyStatic();
     }

   private:
     static int* MyStatic()
     {
       static int mStatic = 0;
       return &mStatic;
     }
   }

The above code has the "bonus" of not requiring a CPP/source file. Again, a method I use for my C++ libraries.

上面的代码具有不需要 CPP/源文件的“好处”。同样,我用于我的 C++ 库的方法。

回答by Alejadro Xalabarder

I follow the idea from Karl. I like it and now I use it as well. I've changed a little bit the notation and add some functionality

我遵循卡尔的想法。我喜欢它,现在我也使用它。我改变了一点符号并添加了一些功能

#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));
}

this outputs

这输出

mystatic value 7
mystatic value 3
is my static 1 0