在 C + + 类中初始化静态变量?

我已经注意到类中的一些函数实际上并没有访问对象,所以我将它们设置为 static。然后编译器告诉我,他们访问的所有变量也必须是静态的——好吧,到目前为止还是可以理解的。我有一堆字符串变量,比如

string RE_ANY = "([^\\n]*)";
string RE_ANY_RELUCTANT = "([^\\n]*?)";

等等。然后我把它们都做成了 static const,因为它们从不改变。然而,我的程序只有当我把它们移出类时才能编译: 否则,MSVC + + 2010抱怨“只有静态常量积分变量可以在类中初始化”。

那太不幸了。有没有变通的办法? 我想把他们留在他们所属的班里。

325470 次浏览

Static member variables must be declared in the class and then defined outside of it!

There's no workaround, just put their actual definition in a source file.


From your description it smells like you're not using static variables the right way. If they never change you should use constant variable instead, but your description is too generic to say something more.

Static member variables always hold the same value for any instance of your class: if you change a static variable of one object, it will change also for all the other objects (and in fact you can also access them without an instance of the class - ie: an object).

They can't be initialised inside the class, but they can be initialised outside the class, in a source file:

// inside the class
class Thing {
static string RE_ANY;
static string RE_ANY_RELUCTANT;
};


// in the source file
string Thing::RE_ANY = "([^\\n]*)";
string Thing::RE_ANY_RELUCTANT = "([^\\n]*?)";

Update

I've just noticed the first line of your question - you don't want to make those functions static, you want to make them const. Making them static means that they are no longer associated with an object (so they can't access any non-static members), and making the data static means it will be shared with all objects of this type. This may well not be what you want. Making them const simply means that they can't modify any members, but can still access them.

I feel it is worth adding that a static variable is not the same as a constant variable.

using a constant variable in a class

struct Foo{
const int a;
Foo(int b) : a(b){}
}

and we would declare it like like so

fooA = new Foo(5);
fooB = new Foo(10);
// fooA.a = 5;
// fooB.a = 10;

For a static variable

struct Bar{
static int a;
Foo(int b){
a = b;
}
}
Bar::a = 0; // set value for a

which is used like so

barA = new Bar(5);
barB = new Bar(10);
// barA.a = 10;
// barB.a = 10;
// Bar::a = 10;

You see what happens here. The constant variable, which is instanced along with each instance of Foo, as Foo is instanced has a separate value for each instance of Foo, and it can't be changed by Foo at all.

Where as with Bar, their is only one value for Bar::a no matter how many instances of Bar are made. They all share this value, you can also access it with their being any instances of Bar. The static variable also abides rules for public/private, so you could make it that only instances of Bar can read the value of Bar::a;

Mike Seymour has given you the right answer, but to add...
C++ lets you declare and define in your class body only static const integral types, as the compiler tells. So you can actually do:

class Foo
{
static const int someInt = 1;
static const short someShort = 2;
// etc.
};

And you can't do that with any other type, in that cases you should define them in your .cpp file.

Since C++11 it can be done inside a class with constexpr.

class stat {
public:
// init inside class
static constexpr double inlineStaticVar = 22;
};

The variable can now be accessed with:

stat::inlineStaticVar

If your goal is to initialize the static variable in your header file (instead of a *.cpp file, which you may want if you are sticking to a "header only" idiom), then you can work around the initialization problem by using a template. Templated static variables can be initialized in a header, without causing multiple symbols to be defined.

See here for an example:

Static member initialization in a class template

Optionally, move all your constants to .cpp file without declaration in .h file. Use anonymous namespace to make them invisible beyond the cpp module.

// MyClass.cpp


#include "MyClass.h"


// anonymous namespace
namespace
{
string RE_ANY = "([^\\n]*)";
string RE_ANY_RELUCTANT = "([^\\n]*?)";
}


// member function (static or not)
bool MyClass::foo()
{
// logic that uses constants
return RE_ANY_RELUCTANT.size() > 0;
}

Just to add on top of the other answers. In order to initialize a complex static member, you can do it as follows:

Declare your static member as usual.

// myClass.h
class myClass
{
static complexClass s_complex;
//...
};

Make a small function to initialize your class if it's not trivial to do so. This will be called just the one time the static member is initialized. (Note that the copy constructor of complexClass will be used, so it should be well defined).

//class.cpp
#include myClass.h
complexClass initFunction()
{
complexClass c;
c.add(...);
c.compute(...);
c.sort(...);
// Etc.
return c;
}


complexClass myClass::s_complex = initFunction();

Some answers including even the accepted answer seem to be a little misleading.

You don't have to

  • Always assign a value to static objects when initializing because that's optional.
  • Create another .cpp file for initializing since it can be done in the same header file.

You can even initialize a static object in the same class scope just like a normal variable using the inline keyword.


Initialize with no values in the same file

#include <string>
class A
{
static std::string str;
static int x;
};
std::string A::str;
int A::x;

Initialize with values in the same file

#include <string>
class A
{
static std::string str;
static int x;
};
std::string A::str = "SO!";
int A::x = 900;

Initialize in the same class scope using the inline keyword

#include <string>
class A
{
static inline std::string str = "SO!";
static inline int x = 900;
};