簡體   English   中英

在C ++類中初始化靜態變量?

[英]Initialize static variables in C++ class?

我注意到我的一些函數實際上沒有訪問對象,所以我把它們做成了static 然后編譯器告訴我他們訪問的所有變量也必須是靜態的 - 到目前為止,這是可以理解的。 我有一堆字符串變量,如

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

在課堂上等等。 然后我把它們都變成了static const因為它們永遠不會改變。 但是,如果我將它們移出類,我的程序只會編譯:否則,MSVC ++ 2010會抱怨“只有靜態常量變量可以在類中初始化”。

那很不幸。 有解決方法嗎? 我想把它們留在他們所屬的班級里面。

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

// 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只意味着它們不能修改任何成員,但仍然可以訪問它們。

Mike Seymour給了你正確的答案,但要加上......
正如編譯器所說,C ++允許您在類體中聲明和定義靜態const整數類型 所以你可以這樣做:

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

並且您不能對任何其他類型執行此操作,在這種情況下,您應該在.cpp文件中定義它們。

從C ++ 11開始,它可以在constexpr的類中完成。

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

現在可以使用以下方法訪問變量:

stat::inlineStaticVar

靜態成員變量必須在類中聲明,然后在其外部定義!

沒有解決方法,只需將其實際定義放在源文件中即可。


從你的描述來看,它聞起來就像你沒有以正確的方式使用靜態變量。 如果他們永遠不會改變你應該使用常量變量,但你的描述太通用了,不能多說些什么。

靜態成員變量對於類的任何實例始終保持相同的值:如果更改一個對象的靜態變量,它也將對所有其他對象進行更改(事實上,您也可以在沒有該類實例的情況下訪問它們 - 即:一個對象)。

我覺得值得補充一點,靜態變量與常量變量不同。

在類中使用常量變量

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

我們會像這樣宣布它

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

對於靜態變量

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

就像這樣使用

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

你看到這里發生了什么。 與Foo的每個實例一起實例化的常量變量,因為Foo被實例化,每個Foo實例都有一個單獨的值,並且Foo根本不能更改它。

與Bar一樣,無論Bar有多少個實例,它們只是Bar :: a的一個值。 它們都共享這個值,您也可以使用它們作為Bar的任何實例來訪問它。 靜態變量也遵循公共/私有規則,因此您可以使只有Bar的實例可以讀取Bar :: a的值;

只是為了補充其他答案。 要初始化復雜的靜態成員 ,可以按如下方式執行:

像往常一樣聲明你的靜態成員。

// 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();

如果您的目標是初始化頭文件中的靜態變量(而不是* .cpp文件,如果您堅持使用“僅標題”慣用語,則可能需要該文件),那么您可以通過使用a來解決初始化問題模板。 模板化的靜態變量可以在標頭中初始化,而不會導致定義多個符號。

請看這里的例子:

類模板中的靜態成員初始化

(可選)將所有常量移動到.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;
}

一些答案似乎有點誤導

你不必......

  • 初始化的時候,因為分配的值是可選 的值賦給一些靜態的對象。
  • 創建另一個.cpp文件以進行初始化,因為它可以在同一個Header文件中完成。

此外,您甚至可以使用inline關鍵字初始化同一類范圍中的靜態對象,就像使用普通變量一樣。


在同一文件中初始化時沒有值

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

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

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

使用inline關鍵字在相同的類范圍中初始化

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM