今回もテンプレートなのですが、今回は関数ではなくクラスの話をします。その名もクラステンプレートです。
では、今回の要点です。
では、いってみましょう。
さて、みなさん CIntArray を思いだして下さい。このクラスは、動的に int 型の配列を確保するためのクラスでした。
では、例えば char 型の配列を使いたければどうすればいいのでしょうか? 普通は CIntArray のソースを使い回したくなると思います。int の部分を char に変えれた CCharArray を作ればそれで終わりなわけです。
しかし、このシリーズに新しい機能を加えたいとします。すると、CIntArray と CCharArray の両方を書き換えなければなりません。CCharPtrArray 、CDoubleArray などいろいろ増やしていけば、もう収拾がつきません。
こういうときはテンプレートの出番です。テンプレートは「処理は同じだが型だけが違っているものを1つにまとめることができる」というものでした。まさに今やりたいことそのものです。
問題は「テンプレートはクラスもサポートしているのか?」ということですが、クラスもテンプレートにできます。テンプレートにしたクラスのことをクラステンプレートと呼びます。
では、CIntArray をテンプレートにして CArray クラスを作ってみましょう。
とりあえず文法のことは置いておいて、次に CArray クラスを示します。これを見ればどんな文法なのかは推測できると思います。文法の詳しい解説は次回に回して、今回はじっくりソースをなめ回してみて下さい。
プログラム1 |
---|
// Array.h #ifndef __ARRAY_H__INCLUDED__ #define __ARRAY_H__INCLUDED__ #include <iostream.h> #include <stdlib.h> #include <memory.h> template <typename TYPE> class CArray { // メンバ変数 private: TYPE* m_pnum; // 動的配列 int m_nNumOf; // 配列の要素数 // コンストラクタ・デストラクタ public: explicit CArray(const int nNumOf); CArray(const CArray <TYPE> & rother); // コピーコンストラクタ virtual ~CArray(); // メンバへのアクセス関数 public: TYPE Get(const int index) const; void Set(const int index, const TYPE value); // メンバの参照 TYPE& operator [](unsigned int index); TYPE& operator [](int index); TYPE operator [](unsigned int index) const; TYPE operator [](int index) const; operator const TYPE*() const; // 配列の直接参照 // インデックスのチェック private: void CheckIndex(const int index) const; // その他の情報の取得 public: bool IsValid() const; // m_pnum の値が有効かどうか int NumOf() const; // 配列の要素数 int SizeOf() const; // 配列のサイズ // コピー public: bool Copy(const CArray <TYPE> & rother); // 配列のコピー CArray <TYPE> & operator =(const CArray <TYPE> & rother); // = 演算子のオーバーロード // 諸関数 private: void Init(); // メンバの初期化 void Release(); // メモリの解放 }; // コピーコンストラクタ template <typename TYPE> CArray <TYPE> ::CArray(const CArray <TYPE> & rother) { Init(); Copy(rother); } // デストラクタ template <typename TYPE> CArray <TYPE> ::~CArray() { Release(); } // メンバへのアクセス関数 template <typename TYPE> TYPE CArray <TYPE> ::Get(const int index) const { CheckIndex(index); return m_pnum[index]; } template <typename TYPE> void CArray <TYPE> ::Set(const int index, const TYPE value) { CheckIndex(index); m_pnum[index] = value; } // インデックスのチェック template <typename TYPE> void CArray <TYPE> ::CheckIndex(const int index) const { if((unsigned int)index < (unsigned int)m_nNumOf) return; cout << "インデックスが不正です!" << endl << "値 : " << index << endl; exit(1); } // メンバの初期化 template <typename TYPE> void CArray <TYPE> ::Init() { m_pnum = NULL; m_nNumOf = 0; } // メモリの解放 // 配列が確保されているときだけメモリを解放します // 解放した後はメンバを初期化します template <typename TYPE> void CArray <TYPE> ::Release() { if(IsValid() == true) { delete [] m_pnum; Init(); } } #endif // #ifnde __ARRAY_H__INCLUDED__ |
プログラム2 |
// TmplCls1.cpp #include <stdio.h> #include "Array.h" int main() { static const char str1[] = "Schroedingerの猫"; CArray <char> str2(sizeof str1); CArray <char> str3(0); int i; for(i = 0; i < str2.NumOf(); i++) str2[i] = str1[i]; cout << str2 << endl; str3 = str2; str3[sizeof str1 - 3] = (char)('犬' >> 8); str3[sizeof str1 - 2] = (char)('犬' & 0xFF); printf("%s\n", (const char*)str3); return 0; } |
実行結果 |
Schroedingerの猫 Schroedingerの犬 |
実は関数の実装をいくつもわざと抜かしているので、それらを追加してみて下さい。追加しないと TempCls.cpp はコンパイルできません。抜かした関数は、コンストラクタ、m_pnum の有効確認関数、要素数・サイズの取得関数、コピー関数、[ ] 演算子4つ、キャスト演算子、= 演算子です。CIntArray のソースを改造して...どうです? できそうですか?
また、「テンプレートは全てヘッダファイルに書く」ことにも注意しましょう。
今回はこれで終わりです。では、要点です。
次回までに CArray をいろいろいじって遊んでみて下さい。それでは。
Last update was done on 2000.12.6
この講座の著作権はロベールが保有しています