2011-02-16 35 views
52

我注意到我的一些函数实际上并没有访问这个对象,所以我把它们做成了static。然后编译器告诉我他们访问的所有变量也必须是静态的 - 至今为止,这是很容易理解的。我有一堆字符串变量,如C++初始化类中的静态变量?

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

等等。然后我把它们全部制作成static const,因为它们从不改变。但是,如果我将它们移出课程,我的程序只会编译:否则,MSVC++ 2010会抱怨:“只有静态常量整型变量可能会在类中初始化”。

那真是不幸。有没有解决方法?我想让他们留在他们所属的班级中。

回答

93

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

// 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]*?)"; 

更新

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

15

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

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


从您的描述中可以看出,您没有使用正确的方式使用静态变量。如果他们永远不会改变,你应该使用常量变量,但是你的描述太笼统,不能说更多的东西。

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

+1

它们现在是const - 它们只需要是静态的,以便我可以在静态成员函数中使用它们。这条规则的原因是什么,他们必须在课堂外声明并定义在课外?这对我来说没有多大意义。 – 2011-02-16 17:37:29

+1

@Felix Dombek:我认为原因是这个类是(/可以)为你编译和链接的每个源文件声明的,但实际变量只能定义一次。这就是你需要明确声明为`extern`在其他源文件中定义的变量的原因。 – peoro 2011-02-16 17:40:54

+1

@peoro:这似乎是合理的!但是为什么它允许使用整数数据类型呢?那也不应该被允许,然后... – 2011-02-16 17:56:09

9

我觉得值得一提的是,静态变量与常量变量不同。使用恒定变量

在类

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

,我们将宣布它像像这样

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

对于静态变量

其用于像这样

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

你会看到这里发生了什么。与Foo的每个实例一起实例化的常量变量(作为Foo实例化)对于Foo的每个实例都有单独的值,并且它根本不能由Foo进行更改。

凡与酒吧,他们只有一个酒吧值::一个不管有多少酒吧的情况下制成。他们都分享这个价值,你也可以通过他们的任何实例来访问它。静态变量也遵守public/private的规则,所以你可以让Bar只能读取Bar :: a的值;

24

迈克·西摩给你正确的答案,但要加...
C++允许声明和在类的身体只定义静态常量整型,因为编译器会告诉。所以,你实际上可以做:

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

你不能做到这一点与任何其他类型的,在情况下,你应该在你的.cpp文件中定义它们。

10

由于C++ 11它可以在类中来完成与constexpr

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

变量现在可以访问:

stat::inlineStaticVar 
2

如果你的目标是初始化你的头文件中的静态变量(而不是* .cpp文件,这可能需要你都坚持“仅头”成语),那么你可以通过使用模板解决初始化问题。模板化静态变量可以在标题中初始化,而不会导致定义多个符号。

在这里看到一个例子:

Static member initialization in a class template

1

或者,将所有的常量.cpp文件没有申报.h文件中。使用匿名命名空间使它们在cpp模块之外不可见。

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

只是添加在其他答案之上。为了初始化一个复杂静态成员,你可以这样做:

声明你的静态成员照常。

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

做一个小函数来初始化你的类,如果它不是微不足道的。这将被称为只是静态成员初始化的一次。 (请注意complexClass的复制构造函数将被使用,所以它应该被很好的定义)。

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

complexClass myClass::s_complex = initFunction();