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

Fel*_*bek 69 c++ static initialization

我注意到我的一些函数实际上没有访问对象,所以我创建了它们static.然后编译器告诉我他们访问的所有变量也必须是静态的 - 到目前为止,这是可以理解的.我有一堆字符串变量,如

string RE_ANY = "([^\\n]*)";
string RE_ANY_RELUCTANT = "([^\\n]*?)";
Run Code Online (Sandbox Code Playgroud)

在课堂上等等.然后我做了所有static const因为他们永远不会改变.但是,如果我将它们移出类,我的程序只会编译:否则,MSVC++ 2010会抱怨"只有静态常量变量可以在类中初始化".

那很不幸.有解决方法吗?我想把它们留在他们所属的班级里面.

Mik*_*our 117

它们不能在类中初始化,但可以在类文件外的源文件中初始化:

// 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]*?)";
Run Code Online (Sandbox Code Playgroud)

更新

我只注意到你的问题的第一线-你希望使这些功能static,你想他们const.制作它们static意味着它们不再与对象相关联(因此它们无法访问任何非静态成员),并且使数据静态意味着它将与此类型的所有对象共享.这可能不是你想要的.制作它们const只是意味着它们无法修改任何成员,但仍然可以访问它们.

  • @Felix:这是不可能的,`const`意味着它不会修改`this` ...而且`static`方法没有`this`. (7认同)
  • 它们不访问对象中的任何内容,只是作为引用参数提供给它们的临时变量。因此,它们可能应该同时是 `const` 和 `static`。 (2认同)
  • @androidplusios.design:我不跟。你需要`string`,因为它是一个变量定义,需要一个类型说明符,类型是`string`。如果您愿意,您可以将 `()` 放在声明符周围,它不会改变含义。 (2认同)
  • @ androidplusios.design:确实看到了.但您必须使用定义语法来定义和初始化它,并且包括类型说明符,无论它是否先前已声明.这就是指定语言的方式. (2认同)
  • @ androidplusios.design:或者,如果你问为什么语法是这样的,它的所有不一致性,冗余性和模糊性:因为它从更简单的语言发展了几十年. (2认同)

San*_* V. 29

Mike Seymour给出了正确答案,但是要添加......
C++允许您在类体中声明和定义静态const整数类型,正如编译器所说.所以你可以这样做:

class Foo
{
    static const int someInt = 1;
    static const short someShort = 2;
    // etc.
};
Run Code Online (Sandbox Code Playgroud)

并且您不能对任何其他类型执行此操作,在这种情况下,您应该在.cpp文件中定义它们.


peo*_*oro 15

静态成员变量必须在类中声明,然后在其外部定义!

没有解决方法,只需将其实际定义放在源文件中即可.


根据您的描述,它闻起来就像您没有以正确的方式使用静态变量.如果他们永远不会改变你应该使用常量变量,但你的描述太通用了,不能多说些什么.

静态成员变量对于类的任何实例始终保持相同的值:如果更改一个对象的静态变量,它也将对所有其他对象进行更改(事实上,您也可以在没有该类实例的情况下访问它们 - 即:一个对象).

  • @Felix Dombek:我认为原因是(/可以)为您编译和链接的每个源文件声明了该类,但实际变量必须只定义一次。这与您需要将其他源文件中定义的变量显式声明为 `extern` 的原因相同。 (3认同)
  • @Felix Dombek:这不是标准投诉。ISO C++ 禁止非常量静态成员的类内初始化。您只能对整型 const 静态成员执行此操作,这是因为静态常量整型变量实际上不会放入内存中,而是会在编译时用作常量。 (3认同)
  • 现在它们是const的-它们也只需要是静态的,这样我就可以在静态成员函数中使用它们。该规则必须在类内部声明并在类外部定义的原因是什么?这对我来说没有多大意义。 (2认同)
  • @peoro:这似乎很合理!但是为什么它允许整数数据类型?那也不应该被允许,然后...... (2认同)
  • @FelixDombek:要回答你的 * 为什么 * C++ 标准不允许这样做的问题,请参阅此处的答案:http://stackoverflow.com/questions/9656941/why-i-cant-initialize-non-const-static -member-or-static-array-in-class (2认同)

0ax*_*ax1 15

从C++ 11开始,它可以在一个类中完成constexpr.

class stat {
    public:
        // init inside class
        static constexpr double inlineStaticVar = 22;
};
Run Code Online (Sandbox Code Playgroud)

现在可以使用以下方法访问变量:

stat::inlineStaticVar
Run Code Online (Sandbox Code Playgroud)

  • 对于整数、双精度、指针等绝对很好。但是,这不适用于问题中的字符串,因为字符串不是文字或引用。 (2认同)

the*_*man 9

我觉得值得补充一点,静态变量与常量变量不同.

在类中使用常量变量

struct Foo{
    const int a;
    Foo(int b) : a(b){}
}
Run Code Online (Sandbox Code Playgroud)

我们会像这样宣布它

fooA = new Foo(5);
fooB = new Foo(10);
// fooA.a = 5;
// fooB.a = 10;
Run Code Online (Sandbox Code Playgroud)

对于静态变量

struct Bar{
    static int a;
    Foo(int b){
        a = b;
    }
}
Bar::a = 0; // set value for a
Run Code Online (Sandbox Code Playgroud)

就像这样使用

barA = new Bar(5);
barB = new Bar(10);
// barA.a = 10;
// barB.a = 10;
// Bar::a = 10;
Run Code Online (Sandbox Code Playgroud)

你看到这里发生了什么.与Foo的每个实例一起实例化的常量变量,因为Foo被实例化,每个Foo实例都有一个单独的值,并且它根本不能被Foo更改.

与Bar一样,无论Bar有多少个实例,它们只是Bar :: a的一个值.它们都共享这个值,您也可以使用它们作为Bar的任何实例来访问它.静态变量也遵循公共/私有规则,因此您可以使只有Bar的实例可以读取Bar :: a的值;


X S*_*ish 9

一些答案甚至包括已接受的答案似乎有点误导

你不必

  • 初始化时始终为静态对象赋值,因为这是可选的
  • 创建另一个.cpp文件进行初始化,因为它可以在同一个头文件中完成

您甚至可以使用inline关键字在同一类范围内初始化静态对象,就像普通变量一样。


在同一个文件中不使用任何值进行初始化

#include <string>
class A
{
    static std::string str;
    static int x;
};
std::string A::str;
int A::x;
Run Code Online (Sandbox Code Playgroud)

使用同一文件中的值进行初始化

#include <string>
class A
{
    static std::string str;
    static int x;
};
std::string A::str = "SO!";
int A::x = 900;
Run Code Online (Sandbox Code Playgroud)

使用inline关键字在同一个类范围内初始化

#include <string>
class A
{
    static inline std::string str = "SO!";
    static inline int x = 900;
};
Run Code Online (Sandbox Code Playgroud)

  • 其中最好的答案。我添加了“内联”,所有链接错误都消失了。 (3认同)
  • “内联变量是 c++ 17 扩展”。这就是我收到的消息 (2认同)

Ser*_*rco 7

只是为了补充其他答案.要初始化复杂的静态成员,可以按如下方式执行:

像往常一样声明你的静态成员.

// myClass.h
class myClass
{
static complexClass s_complex;
//...
};
Run Code Online (Sandbox Code Playgroud)

如果不是这样做的话,可以使用一个小函数来初始化你的类.这只是静态成员初始化的一次.(注意,将使用complexClass的复制构造函数,因此应该很好地定义它).

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

complexClass myClass::s_complex = initFunction();
Run Code Online (Sandbox Code Playgroud)