web-dev-qa-db-ja.com

C ++クラスで静的変数を初期化しますか?

クラス内の一部の関数が実際にオブジェクトにアクセスしていないことに気づいたので、それらをstaticにしました。それからコンパイラは、アクセスするすべての変数も静的でなければならないことを教えてくれました。私は次のような文字列変数をたくさん持っています

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

クラスなどで。その後、変更しないため、すべてをstatic constにしました。ただし、プログラムは、クラスから移動した場合にのみコンパイルされます。それ以外の場合、MSVC++ 2010は「静的定数積分変数のみがクラス内で初期化される可能性があります」と文句を言います。

それは残念です。回避策はありますか?それらが属するクラス内に残したいと思います。

67
Felix Dombek

クラス内で初期化することはできませんが、クラス外、ソースファイルで初期化することができます。

// 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にすることは、単にメンバーを変更できないが、それらにアクセスできることを意味します。

115
Mike Seymour

マイク・シーモアはあなたに正しい答えを与えましたが、追加するには...
C++では、コンパイラーが指示するように、クラス本体でのみ宣言および定義できます静的const整数型。だからあなたは実際に行うことができます:

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

また、他のタイプではこれを行うことはできません。その場合は、.cppファイルでそれらを定義する必要があります。

28
Santiago V.

C++ 11以降では、constexprを使用してクラス内で実行できます。

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

これで、変数にアクセスできます。

stat::inlineStaticVar
15
0ax1

静的メンバー変数は、クラスで宣言してから、その外部で定義する必要があります!

回避策はありません。実際の定義をソースファイルに入れるだけです。


説明から、静的変数を正しい方法で使用していないように感じます。変更されない場合は、代わりに定数変数を使用する必要がありますが、説明は一般的すぎて何も言えません。

静的メンバー変数は、クラスのすべてのインスタンスで常に同じ値を保持します。あるオブジェクトの静的変数を変更すると、他のすべてのオブジェクトでも変更されます(実際、クラスのインスタンスなしでアクセスすることもできます-すなわち:オブジェクト)。

15
peoro

静的変数は定数変数と同じではないことを付け加える価値があると思います。

クラスで定数変数を使用する

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によって変更することはできません。

Barと同様に、Barの値は1つだけです。Barのインスタンスがいくつ作成されても関係ありません。これらはすべてこの値を共有します。また、Barのインスタンスであることにアクセスできます。静的変数はpublic/privateの規則も順守しているため、BarのインスタンスのみがBar :: a;の値を読み取ることができるようにできます。

9
thecoshman

他の回答の上に追加するだけです。 複雑な静的メンバーを初期化するには、次のようにします。

通常どおり、静的メンバーを宣言します。

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

クラスを初期化するのが簡単でない場合は、小さな関数を作成します。これは、静的メンバーが初期化されるときに1回だけ呼び出されます。 (complexClassのコピーコンストラクターが使用されるため、適切に定義する必要があります)。

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

complexClass myClass::s_complex = initFunction();
7
Sergio Basurco

目的がヘッダーファイル内の静的変数を初期化することである場合(* .cppファイルの代わりに、「ヘッダーのみ」のイディオムに固執している場合)、aを使用して初期化問題を回避できます。テンプレート。テンプレート化された静的変数は、複数のシンボルを定義せずに、ヘッダーで初期化できます。

例についてはこちらをご覧ください。

クラステンプレートでの静的メンバーの初期化

2
Mark Lakata

オプションで、すべての定数を.hファイルで宣言せずに.cppファイルに移動します。匿名の名前空間を使用して、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;
}
1
RuslanK

いくつかの答えは誤解を招く少しのようです。

する必要はありません

  • 初期化時に静的オブジェクトに値を割り当てます。値の割り当てはオプションです。
  • 別の.cppファイルを作成して初期化します。これはHeaderファイルで同様に実行できます。

#ifndef CLASS_A_H
#define CLASS_A_H
#include <string>
class A
{
private:
    static std::string str;
    static int x;
};
// Initialize with no values
std::string A::str;
int A::x;
// Initialize with values
//std::string A::str = "SO!";
//int A::x = 900;
#endif
1
X Stylish