🖥️

【C++言語入門】 第20回 静的メンバ

に公開

https://youtu.be/qtK1oAGjKOk

四国めたん
\textcolor{pink}{四国めたん: }教師役ですわ

ずんだもん
\textcolor{lime}{ずんだもん: }生徒役なのだ

\footnotesize \textcolor{pink}{四国めたん:} こんにちは。四国めたんです

\footnotesize \textcolor{lime}{ずんだもん:} ずんだもんなのだ。こんにちはなのだ

\footnotesize \textcolor{pink}{四国めたん:} 今回は 静的メンバ についてお話ししますわ

\footnotesize \textcolor{lime}{ずんだもん:} 静的メンバ

\footnotesize \textcolor{pink}{四国めたん:} はい、static修飾子を付加したメンバ変数やメソッドのことですわね

\footnotesize \textcolor{lime}{ずんだもん:} 詳しく教えて欲しいのだ

\footnotesize \textcolor{pink}{四国めたん:} 判りましたわ

静的メンバ変数

\footnotesize \textcolor{pink}{四国めたん:} まず最初は 静的メンバ変数 ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 静的メンバ変数

\footnotesize \textcolor{pink}{四国めたん:} はい、クラスのメンバ変数の一種ですわ

\footnotesize \textcolor{lime}{ずんだもん:} どのように記述するのだ?

\footnotesize \textcolor{pink}{四国めたん:} クラス内のメンバ変数にstaticを付加して宣言しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 具体的に教えて欲しいのだ

\footnotesize \textcolor{pink}{四国めたん:} 例えばこんな感じですわ

class クラス名 {
  static 型 メンバ変数名;
    :
    :
}

\footnotesize \textcolor{lime}{ずんだもん:} なるほど、このようにstaticを付加したメンバ変数を 静的メンバ変数 と呼ぶのか...

\footnotesize \textcolor{pink}{四国めたん:} はい、 静的メンバ変数 は、基本的にクラスから生成された全てのインスタンスで共有されますわ

\footnotesize \textcolor{lime}{ずんだもん:} そうなのか?

\footnotesize \textcolor{pink}{四国めたん:} また、アクセス指定子がpublic:である場合には、直接アクセスすることも可能ですわ

class クラス名 {
 public:
  static 型 メンバ変数名;
    :
    :
}

void main() {
  クラス名::メンバ変数名 = 初期値;
}

\footnotesize \textcolor{lime}{ずんだもん:} その辺りは普通のメンバ変数と変わりないのだ

\footnotesize \textcolor{pink}{四国めたん:} ただ、 静的メンバ変数 に外部からアクセスする場合にはスコープ演算子"::"を用いますわ

\footnotesize \textcolor{lime}{ずんだもん:} クラス名::メンバ変数名となっているのだ

静的メンバ変数の初期化

\footnotesize \textcolor{lime}{ずんだもん:} ところで 静的メンバ変数 の初期化はどのようにおこなうのだ?

\footnotesize \textcolor{pink}{四国めたん:} public:静的メンバ変数 は、メイン関数の初めなどでクラス名::メンバ変数名 = 初期値;などとして初期化できますわ

\footnotesize \textcolor{lime}{ずんだもん:} ふむふむ

\footnotesize \textcolor{pink}{四国めたん:} しかしprivate:protected:の場合にはこの方法は使えませんわ

\footnotesize \textcolor{lime}{ずんだもん:} うむ

\footnotesize \textcolor{pink}{四国めたん:} 静的メンバ変数の初期化は、グローバル変数の初期化のような形式でおこなうのが一般的ですわ

\footnotesize \textcolor{lime}{ずんだもん:} そうなのか?

\footnotesize \textcolor{pink}{四国めたん:} 例えばこんな感じですわ

class クラス名 {
  static 型 メンバ変数名;
    :
    :
}

型 クラス名::メンバ変数名 = 初期値;

\footnotesize \textcolor{lime}{ずんだもん:} クラス定義の外で初期値を代入しているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、なおクラス定義の外で初期値を代入する場合には、staticは付けませんわ

\footnotesize \textcolor{lime}{ずんだもん:} 付けるとどうなるのだ?

\footnotesize \textcolor{pink}{四国めたん:} staticを付けるとエラーとなりますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} なお、一般的にクラスをヘッダーファイル".h"で定義している場合には、 静的メンバ変数 の初期化はソースファイル".cpp"側で行いますわ

\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ

定数

\footnotesize \textcolor{pink}{四国めたん:} ところで、 静的メンバ変数constを付加することで、クラスに属する定数を定義することができますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのようにするのだ?

\footnotesize \textcolor{pink}{四国めたん:} 例えばこんな感じですわ

class クラス名 {
  static const 型 メンバ変数名;
    :
    :
}

const 型 クラス名::メンバ変数名 = 初期値;

\footnotesize \textcolor{lime}{ずんだもん:} ただ単に 静的メンバ変数constを付けただけなのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、当然ですが、この定数は参照することはできますが、値を変更することはできませんわ

\footnotesize \textcolor{lime}{ずんだもん:} まぁ、定数なので当然なのだ

\footnotesize \textcolor{pink}{四国めたん:} 初期化の方法は 静的メンバ変数 の場合と同じですわ

\footnotesize \textcolor{lime}{ずんだもん:} 初期化にもconstが付いているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、初期化の際にはstaticは付けませんが、constは必要ですわね

\footnotesize \textcolor{lime}{ずんだもん:} ところで、これってグローバル定数の定義と変わらないのでは?

\footnotesize \textcolor{pink}{四国めたん:} その通りですわね

\footnotesize \textcolor{lime}{ずんだもん:} なぜ、わざわざクラス内で定義するのだ?

\footnotesize \textcolor{lime}{ずんだもん:} 面倒なだけな気がするのだが...

\footnotesize \textcolor{pink}{四国めたん:} アクセス指定にもよりますが、クラスに属する定数はクラス内もしくは派生クラス内からしかアクセスできませんわ

\footnotesize \textcolor{lime}{ずんだもん:} アクセスできる範囲を限定できるのがメリットと云うことか...

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} また、クラスに密接に関係する定数であることを明示することもできますわね

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} ですので、できるのであればグローバルな定数よりもクラスに属する定数の方を使うほうがいいですわね

静的メンバ関数

\footnotesize \textcolor{pink}{四国めたん:} 次は 静的メンバ関数 ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 静的メンバ関数

\footnotesize \textcolor{pink}{四国めたん:} はい、クラスのメソッドの一種ですわ

\footnotesize \textcolor{lime}{ずんだもん:} どのように記述するのだ?

\footnotesize \textcolor{pink}{四国めたん:} クラス内のメソッドにstaticを付加して宣言しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 具体的に教えて欲しいのだ

\footnotesize \textcolor{pink}{四国めたん:} 例えばこんな感じですわ

class クラス名 {
 public:
  static 型 メソッド名(引数...) { 処理 };
    :
    :
}

\footnotesize \textcolor{lime}{ずんだもん:} このようにstaticを付加したメソッドを 静的メンバ関数 と呼ぶのか...

\footnotesize \textcolor{pink}{四国めたん:} はい、 静的メンバ関数 は通常のメソッドと同じくインスタンス名.メソッド名で呼び出すことができますわ

\footnotesize \textcolor{lime}{ずんだもん:} ふむふむ

\footnotesize \textcolor{pink}{四国めたん:} それに加えてスコープ演算子"::"を用いてクラス名::メソッド名で呼び出すことも可能ですわ

\footnotesize \textcolor{lime}{ずんだもん:} えぇっ、そうなのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、 静的メンバ関数 はクラスオブジェクトを生成しなくても呼び出せるのですわ

\footnotesize \textcolor{lime}{ずんだもん:} それはすごいのだ

\footnotesize \textcolor{pink}{四国めたん:} たた制約もあり、 静的メンバ関数 からは 静的メンバ変数 以外のメンバ変数へのアクセスができませんわ

\footnotesize \textcolor{lime}{ずんだもん:} う~ん、そこは微妙なのだ

\footnotesize \textcolor{pink}{四国めたん:} まぁ当然といえば当然ですわ

\footnotesize \textcolor{lime}{ずんだもん:} そうなのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、通常のメンバ変数はクラスオブジェクト生成と同時に生成されますわね

\footnotesize \textcolor{lime}{ずんだもん:} たしかにその通りなのだ

\footnotesize \textcolor{pink}{四国めたん:} 一方でクラスオブジェクトを生成しないで使用する 静的メンバ関数 は、生成されていないメンバ変数にアクセスできないのは明らかですわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} ところでヘッダーファイル".h"内のクラス定義で 静的メンバ関数staticを付加して宣言するとしますわね

\footnotesize \textcolor{lime}{ずんだもん:} ふむふむ

\footnotesize \textcolor{pink}{四国めたん:} そして別のソースファイル".cpp"で 静的メンバ関数 を定義する場合は通常のメソッドと同様に記述しますわ

\footnotesize \textcolor{lime}{ずんだもん:} うん?定義にstaticを付けなくていいのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、定義にはstaticは不要ですわ

クラス名.h
class クラス名 {
 public:
  static 型 メソッド名(引数...);
    :
    :
}
クラス名.cpp
型 メソッド名(引数...) { 処理 };

具体例

\footnotesize \textcolor{pink}{四国めたん:} いろいろとお話してきましたが、具体例を見てみましょう

#include <iostream>

class Count {
  static int counter_;

 public:
  Count() { counter_++; }
  virtual ~Count() { counter_--; }

  static void Show() {
    std::cout << "現在のオブジェクト数: " << counter_ << std::endl;
    return;
  }
};

int Count::counter_ = 0;

int main(int argc, char* argv[]) {
  Count* p0 = new Count;
  p0->Show();
  Count* p1 = new Count;
  p1->Show();
  delete p0;
  p0 = nullptr;
  Count::Show();
  delete p1;
  p1 = nullptr;
  Count::Show();
  return 0;
}

具体例

\footnotesize \textcolor{pink}{四国めたん:} まずCountクラスですが、 静的メンバ変数 として"counter_"を宣言していますわ

\footnotesize \textcolor{lime}{ずんだもん:} クラス定義後に初期化をint Count::counter_ = 0;としておこなっているのだ

\footnotesize \textcolor{pink}{四国めたん:} コンストラクタで"はcounter_"をインクリメントし、デストラクタで"counter_"をデクリメントしていますわ

\footnotesize \textcolor{lime}{ずんだもん:} ふむふむ

\footnotesize \textcolor{pink}{四国めたん:} 結果として"counter_"は生成されているインスタンス数を保持することになりますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} メイン関数内の最初では、生成したインスタンス"p0"や"p1"からShowメソッドを呼び出していますわ

\footnotesize \textcolor{lime}{ずんだもん:} どちらのインスタンスからShowメソッドを呼び出しても、結果として"counter_"の数が表示されているのだ

\footnotesize \textcolor{pink}{四国めたん:} 次に、インスタンスをdeleteすると、インスタンスからShowメソッドを呼び出せなくなりますわ

\footnotesize \textcolor{lime}{ずんだもん:} たしかに...

\footnotesize \textcolor{pink}{四国めたん:} なので、クラスの 静的メンバ関数 としてCount::Show();のように呼び出していますわ

\footnotesize \textcolor{lime}{ずんだもん:} 結果として"counter_"の数が表示されているのだ

\footnotesize \textcolor{pink}{四国めたん:} そうですわね

\footnotesize \textcolor{lime}{ずんだもん:} ところでメイン関数内で、Countのインスタンス生成時にnew Countと括弧"()"が抜けているのだが...

\footnotesize \textcolor{pink}{四国めたん:} はい、クラスのインスタンス生成時に引数が必要ない場合には、括弧"()"を省略できるのですわ

\footnotesize \textcolor{lime}{ずんだもん:} そうなのか?

\footnotesize \textcolor{pink}{四国めたん:} ただ、あまり良い書き方ではないので、括弧"()"は付けた方が良いですわね

\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ

\footnotesize \textcolor{pink}{四国めたん:} 今回は、このような書き方があるということを示すために、あえて括弧"()"を省略しましたわ

まとめ

\footnotesize \textcolor{pink}{四国めたん:} お疲れさまでした

\footnotesize \textcolor{lime}{ずんだもん:} おつかれさまなのだ

\footnotesize \textcolor{pink}{四国めたん:} 以上で 静的メンバ を終わりますわ

Discussion