前回の問題点を解決するため、staticメンバについて説明します。
staticキーワードについてはC言語編で説明しました。
「プログラムの実行前に用意される」というのが特徴です。
この性質を利用したのが「staticメンバ変数」や「staticメンバ定数」「staticメンバ関数」などです。
staticキーワードを付けた変数や定数、関数はクラスが実体を持つ前から用意されます。
早速試してみましょう。
とりあえず、クラスの宣言部分だけ書いてみます。
<sample program cpp055-01>
class Sample { public: static int m_variable; static const int CONSTANT; static void Function(); }; |
上から、static変数、static定数、static関数です。
staticでない変数や定数の初期値は、コンストラクタ関数の初期化リストで設定していました。
しかし、static変数や定数はコンストラクタ関数が呼び出される前には用意されていますので、初期化の方法も異なります。
では、初期化と関数本体を加えてみます。
<sample program cpp055-02>
#include <iostream>
class Sample {
public:
static int m_variable;
static const int CONSTANT;
static void Function();
};
int main()
{
return 0;
}
int Sample::m_variable = 0;
const int Sample::CONSTANT = 123;
void Sample::Function()
{
std::cout << "Function Call" << std::endl;
}
|
変数や定数はクラス宣言の外で初期値を代入します。
クラスの外に書くため、所属を書かなければいけません。
ファイル分割をした後はcppファイルに書く事になります。
では、実際に使ってみましょう。
<sample program cpp055-03>
#include <iostream> class Sample { public: static int m_variable; static const int CONSTANT; static void Function(); }; int main() { std::cout << "m_variable = " << Sample::m_variable << std::endl; std::cout << "CONSTANT = " << Sample::CONSTANT << std::endl; Sample::Function(); return 0; } int Sample::m_variable = 0; const int Sample::CONSTANT = 123; void Sample::Function() { std::cout << "Function Call" << std::endl; } |
<実行結果>
m_variable = 0 CONSTANT = 123 Function Call 続行するには何かキーを押してください・・・
main関数でSampleクラスの実体は作っていません。
所属を表す「スコープ解決演算子」を使ってSampleクラスに所属している○○という書き方でアクセス出来ます。
これを使えば前回の問題もクリア出来ます。
<sample program cpp055-04>
#include <iostream> #include <vector> class Card { public: static const int SUIT; static const int NUMBER; static const int CARD_MAX; }; class Deck { public: void ShowDeck(); private: std::vector<Card> vecCard; }; int main() { return 0; } const int Card::SUIT = 4; const int Card::NUMBER = 13; const int Card::CARD_MAX = SUIT * NUMBER; void Deck::ShowDeck() { for (int i = 0; i < Card::CARD_MAX; i++) { } } |
Cardクラスの実体を作る事無く、他のクラスで定数として扱えるようになりました。
staticメンバは、クラスの実体を複数作成しても1つしか存在しません。
サンプルを作成して確認します。
<sample program cpp055-05>
#include <iostream> class Slime { public: Slime(); void ShowCounter(); private: static int counter; }; int main() { return 0; } int Slime::counter; Slime::Slime() { counter++; } void Slime::ShowCounter() { std::cout << "Number of Slime = " << counter << std::endl; } |
このクラスには、static変数メンバとしてcounterが用意されています。
staticメンバ変数は自動的に0で初期化されています。
コンストラクタ関数で、counterに1を加えています。
どのような動きをするか、main関数にコードを追加して試してみましょう。
<sample program cpp055-06>
#include <iostream>
class Slime {
public:
Slime();
void ShowCounter();
private:
static int counter;
};
int main()
{
Slime slime1;
slime1.ShowCounter();
return 0;
}
int Slime::counter;
Slime::Slime()
{
counter++;
}
void Slime::ShowCounter()
{
std::cout << "Number of Slime = " << counter << std::endl;
}
|
<実行結果>
Number of Slime = 1 続行するには何かキーを押してください・・・
ここまでは当たり前のように感じます。
では、次のコードを追加して実行してください。
<sample program cpp055-07>
#include <iostream>
class Slime {
public:
Slime();
void ShowCounter();
private:
static int counter;
};
int main()
{
Slime slime1;
Slime slime2;
slime1.ShowCounter();
return 0;
}
int Slime::counter;
Slime::Slime()
{
counter++;
}
void Slime::ShowCounter()
{
std::cout << "Number of Slime = " << counter << std::endl;
}
|
<実行結果>
Number of Slime = 2 続行するには何かキーを押してください・・・
クラスの実体を1つ追加して、「slime1」のShowCounter関数を呼び出しました。
結果は「2」になっています。
これは、「slime2」のコンストラクタ関数が動作した際にcounterを1増やした結果です。
counterはstaticメンバのため、「slime1」も「slime2」も同じ変数を参照する事になります。
もっと増やしてみましょう。
<sample program cpp055-08>
#include <iostream>
class Slime {
public:
Slime();
void ShowCounter();
private:
static int counter;
};
int main()
{
Slime slime1;
Slime slime2;
Slime slimes[10];
slime1.ShowCounter();
return 0;
}
int Slime::counter;
Slime::Slime()
{
counter++;
}
void Slime::ShowCounter()
{
std::cout << "Number of Slime = " << counter << std::endl;
}
|
<実行結果>
Number of Slime = 12 続行するには何かキーを押してください・・・
今、クラスの実体がいくつあるのか調べる事が出来ています。
色々な使い道がありますので、覚えておくと便利です。