2011-02-16 36 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();