静的メソッドと変数
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 31/104。
静的メンバはすべてのオブジェクト間で共有されることを学びました。次に、静的変数と並行して静的メソッドを適切に定義し、使用する方法を探ってみましょう。
クラス内で宣言された静的変数は、通常ソースファイル内など、クラスの外で定義される必要があります。これは、静的メンバがすべてのオブジェクトによって共有される、ただ1つの記憶場所を必要とするためです:
class Counter {
static int count; // 宣言のみ
public:
Counter() { count++; }
~Counter() { count--; }
static int getCount() { // 静的メソッド
return count;
}
};
// 定義 - クラス外で必要
int Counter::count = 0;静적メソッドは、オブジェクトではなくクラスに属します。これには重要な結果が伴います。静的メソッドは特定のオブジェクトに対して呼び出されないため、インスタンスメンバにアクセスしたり、this ポインタを使用したりすることはできません。
class MathUtils {
static double pi;
public:
static double circleArea(double radius) {
return pi * radius * radius; // 静적メンバにアクセスできます
}
};
double MathUtils::pi = 3.14159;
// オブジェクトなしで呼び出されます
double area = MathUtils::circleArea(5.0);静的メソッドは、オブジェクトの状態を必要としないユーティリティ関数、オブジェクトを作成するファクトリメソッド、または静的データへのアクセスに最適です。オブジェクトのインスタンスを必要としないため、クラス名とスコープ解決演算子を使用して呼び出します:ClassName::methodName()。
チャレンジ
簡単オブジェクトのインスタンスを必要とせずに、クラスレベルの機能を提供するために静的メソッドと静的変数がどのように連携するかを示す、ユニークなID生成システムを構築しましょう。
コードを整理するために2つのファイルを作成します:
IDGenerator.h: 連続したユニークなIDを生成するIDGeneratorクラスを定義します。クラスには以下のものを含める必要があります:- 次に割り当てられるIDを追跡するプライベートな静的メンバ
nextId(1000から開始) - すべてのIDのカスタマイズ可能な接頭辞を格納するプライベートな静的メンバ
prefix(string) - 接頭辞を変更する静的メソッド
setPrefix(const std::string& p) - 接頭辞と現在のID番号を組み合わせた文字列を返し、次の呼び出しのために
nextIdをインクリメントする静的メソッドgetNextId() - カウンタをインクリメントせずに、次のIDが何になるかを返す静的メソッド
peekNextId() - これまでに生成されたIDの数を返す静的メソッド
getGeneratedCount()(ヒント:開始値と現在のnextIdから計算します) nextIdを1000にリセットする静的メソッドreset()
クラス定義の後のクラス外で静的メンバを定義することを忘れないでください。
prefixを"ID-"で初期化します。- 次に割り当てられるIDを追跡するプライベートな静的メンバ
main.cpp: オブジェクトを作成せずに、クラス名を使用して静的メソッドを呼び出すデモンストレーションを行います。入力からカスタム接頭辞を読み取り、以下の処理を行います:peekNextId()を使用して"Peek: <peeked_id>"と出力しますgetNextId()を使用して3つのIDを生成し、それぞれを"Generated: <id>"として出力します- 生成されたIDの数を示す
"Count: <count>"を出力します setPrefix()を使用して、入力値で接頭辞を変更します- さらに2つのIDを生成し、それぞれを
"Generated: <id>"として出力します - 再び
"Count: <count>"を出力します reset()を呼び出します"After reset - Peek: <peeked_id>"と出力します"After reset - Count: <count>"と出力します
IDGenerator オブジェクトを一度も作成していないことに注目してください。すべてのメソッドは IDGenerator::methodName() を使用してクラスに対して直接呼び出されます。これが静的メソッドの主な特徴です。つまり、特定のインスタンスではなく、クラス自体に属しているのです。
ヘッダーファイルに <string> と <iostream> をインクルードし、ヘッダーガードを忘れないようにしてください。
チートシート
クラス内で宣言された静的変数は、クラスの外で定義されなければなりません。静的メンバは、すべてのオブジェクトで共有されるただ1つの記憶場所を必要とします:
class Counter {
static int count; // 宣言のみ
public:
Counter() { count++; }
static int getCount() {
return count;
}
};
// 定義 - クラスの外で必要
int Counter::count = 0;静的メソッドはオブジェクトではなくクラスに属します。静的メソッドは特定のオブジェクトに対して呼び出されないため、インスタンスメンバにアクセスしたり、thisポインタを使用したりすることはできません:
class MathUtils {
static double pi;
public:
static double circleArea(double radius) {
return pi * radius * radius; // 静的メンバにアクセス可能
}
};
double MathUtils::pi = 3.14159;
// クラス名を使用してオブジェクトなしで呼び出される
double area = MathUtils::circleArea(5.0);静的メソッドは、クラス名とスコープ解決演算子を使用して呼び出されます:ClassName::methodName()。これらは、オブジェクトの状態を必要としないユーティリティ関数、ファクトリメソッド、または静的データへのアクセスに最適です。
自分で試してみよう
#include <iostream>
#include <string>
#include "IDGenerator.h"
using namespace std;
int main() {
// 入力からカスタムプレフィックスを読み取る
string customPrefix;
cin >> customPrefix;
// TODO: peekNextId() を使用して "Peek: <peeked_id>" を出力する
// TODO: getNextId() を使用して3つのIDを生成し、それぞれを "Generated: <id>" として出力する
// TODO: 生成されたIDの数を示す "Count: <count>" を出力する
// TODO: setPrefix() を使用して、入力値でプレフィックスを変更する
// TODO: さらに2つのIDを生成し、それぞれを "Generated: <id>" として出力する
// TODO: 再度 "Count: <count>" を出力する
// TODO: reset() を呼び出す
// TODO: "After reset - Peek: <peeked_id>" を出力する
// TODO: "After reset - Count: <count>" を出力する
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス