今回もテンプレートなのですが、今回は関数ではなくクラスの話をします。その名もクラステンプレートです。
では、今回の要点です。
では、いってみましょう。
さて、みなさん 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
この講座の著作権はロベールが保有しています