クラステンプレート
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 65/104。
関数テンプレートが型に依存しない関数を書くことを可能にするのと同様に、クラステンプレートを使用すると、型に依存しないクラスを作成できます。これは std::vector のようなコンテナが動作する仕組みです。つまり、構造を一度定義すれば、コンパイラが使用する各型に対して特定のバージョンを生成します。
template <typename T>
class Box {
T value;
public:
Box(T v) : value(v) {}
T getValue() const { return value; }
void setValue(T v) { value = v; }
};
int main() {
Box<int> intBox(42);
Box<std::string> strBox("Hello");
std::cout << intBox.getValue() << std::endl; // 42
std::cout << strBox.getValue() << std::endl; // Hello
}関数テンプレートとは異なり、クラステンプレートからオブジェクトを作成する際は、アングルブラケットを使用して型を明示的に指定する必要があります。その後、コンパイラはその特定の型に対して完全なクラス定義を生成します。
クラステンプレートは、複数の型パラメータや、整数のような非型パラメータを持つこともできます。
template <typename T, int Size>
class FixedArray {
T data[Size];
public:
T& operator[](int index) { return data[index]; }
int size() const { return Size; }
};
FixedArray<double, 5> arr; // 5つのdouble型の配列
arr[0] = 3.14;クラスの外でメンバ関数を定義する場合、テンプレート宣言を繰り返す必要があります:
template <typename T>
class Container {
T* data;
public:
Container();
~Container();
};
template <typename T>
Container<T>::Container() : data(nullptr) {}
template <typename T>
Container<T>::~Container() { delete data; }クラステンプレートはC++におけるジェネリックプログラミングの基盤であり、あらゆる型で動作する再利用可能なデータ構造を記述することを可能にします。
チャレンジ
簡単クラステンプレートを使用して、あらゆる種類のデータを保持できる柔軟なコンテナである汎用ストレージシステムを構築しましょう。テンプレートクラスをヘッダーファイルにまとめ、メインプログラムでさまざまな型に対する汎用性を実証します。
2つのファイルを作成します:
Storage.h: 単一の値を保持し、いくつかの便利な操作を行うStorageという名前のクラステンプレートを定義します。Storageテンプレートには以下を含める必要があります:- 格納された値を保持するプライベートメンバ
- 初期値を受け取るコンストラクタ
- 格納された値を返す
getValue()メソッド - 格納された値を更新する
setValue()メソッド - 値が型 T のデフォルトコンストラクタで生成された値と等しい場合に
trueを返し、そうでない場合にfalseを返すisEmpty()メソッド
また、2つの関連する値を格納する、2つの型パラメータを持つ
Pairという名前のクラステンプレートも作成します:- 1番目と2番目の値(異なる型の可能性があります)のためのプライベートメンバ
- 両方の値を初期化するコンストラクタ
- 各値を取得する
getFirst()およびgetSecond()メソッド (<first>, <second>)と出力するdisplay()メソッド
main.cpp: 4つの入力(それぞれ別の行)を読み取ります:- 整数の値
- 新しい整数の値
- 文字列の値
- double型の値
以下の手順でテンプレートを実証してください:
- 最初の整数で
Storage<int>を作成し、Int storage: <value>と出力します。 setValue()を使用して2番目の整数で更新し、Updated: <value>と出力します。- 入力された文字列で
Storage<std::string>を作成し、String storage: <value>と出力します。 - 文字列ストレージが空かどうかを確認し、
Is empty: <true/false>と出力します(trueまたはfalseを出力)。 - 文字列と double 値で
Pair<std::string, double>を作成し、display()を呼び出します。 - 両方の整数入力で
Pair<int, int>を作成し、display()を呼び出します。
例えば、入力が 42、100、Hello、3.14 の場合:
Int storage: 42
Updated: 100
String storage: Hello
Is empty: false
(Hello, 3.14)
(42, 100)同じ Storage テンプレートが整数と文字列でシームレスに動作し、Pair が異なる型をどのように組み合わせることができるかに注目してください。コンパイラは、使用する型の組み合わせごとに個別のクラス定義を生成します。単一型テンプレートには template <typename T> 構文を、複数の型パラメータを持つテンプレートには template <typename T, typename U> 構文を使用することを忘れないでください。
自分で試してみよう
#include <iostream>
#include <string>
#include "Storage.h"
using namespace std;
int main() {
// 入力を読み込む
int intValue1;
int intValue2;
string strValue;
double doubleValue;
cin >> intValue1;
cin >> intValue2;
cin >> strValue;
cin >> doubleValue;
// TODO: 最初の整数で Storage<int> を作成し、「Int storage: <value>」と出力する
// TODO: setValue() を使用して2番目の整数で更新し、「Updated: <value>」と出力する
// TODO: 文字列入力で Storage<std::string> を作成し、「String storage: <value>」と出力する
// TODO: 文字列ストレージが空かどうかを確認し、「Is empty: true/false」と出力する
// TODO: 文字列と double で Pair<std::string, double> を作成し、display() を呼び出す
// TODO: 両方の整数で Pair<int, int> を作成し、display() を呼び出す
return 0;
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス