第五回-01 : テンプレート

第四回の課題2(1) を思い出そう。 この問題では、第四回-04 に登場した array クラスを、
「int 型を格納するものから char 型を格納するもの」に変更してもらった。

やってみるとわかることだが、実際の作業はエディタなどの「置換」機能を 使えば簡単にできるような内容であった。

しかし、array クラスは汎用に使えそうなクラスであるのに、 使う型が変わるたびにクラス定義を変更していたのでは使いにくい。
array クラスが、どんな型に対しても、変更なしに使えるようになると便利である。
そのような用途で用いられるのがテンプレートという機能である。

具体的には、array クラスにおいて、「char」や「int」などと記述する変わりに、
<class T> という仮想的なクラスを用いて記述するのである。("T" の部分は変数のように自分の好きな名前をつけて構わない)

そして、実際に main 関数などで利用するたびに、 T を char や int で置き換えて使う、というイメージである。

実際に array クラスをテンプレートクラスに変更した例を以下に示す。 変更点はで示した。
「new int[10];」 などとなっていた部分が「new T[10];」などと変更されていることがわかるだろう。

#include <iostream>
#include <cstdlib>  // for exit(1)
using namespace std;

template <class T> class array{   // クラス宣言
    T *p;   // 配列の先頭を指すポインタ
    int size;   
public:
    array();                // デフォルトコンストラクタ
    array(int sz);          // 要素数を指定するコンストラクタ
    array(const array &a);  // コピーコンストラクタ

    ~array(){ delete[] p;}  // デストラクタ

    array &operator=(const array &a); 
    T &operator[](int i); // [] 演算子の多重定義
    
    int getsize(){ return size; }  // 配列のサイズ取得

};

template <class T> array<T>::array(){  // デフォルトコンストラクタ
      p = new T[10];
      if(!p) exit(1);
      size = 10;

//      cout << "デフォルトコンストラクタ\n";
}

template <class T> array<T>::array(int sz){  // 要素数を指定するコンストラクタ
      p = new T[sz];
      if(!p) exit(1);
      size = sz;

//      cout << "要素数を指定するコンストラクタ\n";
}


template <class T> array<T>::array(const array &a){   // コピーコンストラクタ
  size = a.size;

  p = new T[size];

  if(!p) exit(1);

  for(int i=0 ; i<a.size ; i++) p[i] = a.p[i];  // 内容をコピー

//  cout << "コピーコンストラクタ\n";
}

template <class T> array<T> &array<T>::operator=(const array &a){

  delete[] p;

  size = a.size;

  p = new T[size];

  if(!p) exit(1);

  for(int i=0 ; i<a.size ; i++) p[i] = a.p[i];  // 内容をコピー

  cout << "代入演算子\n";

  return(*this);
}

template <class T> T &array<T>::operator[](int i){    // [] 演算子の多重定義
  if(i<0){
    cout << "配列の範囲から外れています!";
    return p[0];
  }else if(i>=size){
    cout << "配列の範囲から外れています!";
    return p[size-1];
  }else{
    return p[i];
  }
} 

int main(){ //  main 関数

  cout << "***** array を int で利用 *****\n";

  array<int> a1(10);

  a1[0] = 0;
  a1[1] = 1;
  a1[2] = 2;
  a1[3] = 3;

  for(int i=0 ; i<4 ; i++) cout << a1[i];

  cout << "\n";

  cout << "***** array を char で利用 *****\n";

  array<char> a2(10);

  a2[0] = 'T';
  a2[1] = 'e';
  a2[2] = 's';
  a2[3] = 't';

  for(int i=0 ; i<4 ; i++) cout << a2[i];

  cout << "\n";

  return 0;
}


そして、main 関数における利用部においては、 「array<int> a1(10);」や「array<char> a1(10);」のように型を指定して利用している。

関数宣言の際のテンプレート指定はやや複雑であるが、これは無理に覚えようとせずに、 記述するたびに調べながら書けば良いであろう。



←第四回演習第五回-02 : リストの概念→

第五回トップページへ

クラスから入る C++