next up previous
Next: イテレータ Up: C++のめんどくさい利用法 Previous: C++のめんどくさい利用法

テンプレート

C++で連結リストを作ってみよう.オーソドックスに作ればこんな感じになる.

class List {
  protected:
    int nakami;
    List *next;
  public:
    ....
};
このリストでは,中身(nakami)は整数型だ.しかし,実際にリストに 入れたいものはさまざまだから,中身ごとにクラスを作り直さなけれ ばならない.こんなときは,継承を使って記述をシンプルにすることが できる.
class ListBase {
  protected:
    ListBase *next;
  public:
    ....
};

class IntList : public ListBase {
  pritected:
    int nakami;
  public:
    ...
};
これで良さそうだが,ちょっと問題が出てくる.例として, リストの全要素を表示するメンバ関数を作ってみよう.
class IntList {
    ...
  public:
    ...
    void print() {
        IntList *p = this;
        while (p) {
            printf("%d¥n",p->nakami);
            p = (IntList*)next;
        }
    }
};
nextの型はListBase*なので,IntListの中で nextを使う場合には,常にIntList*にキャストしなければならない. この程度の例なら抜け道はあるが,本質的にはリストをたどる処理を するたびにキャストが必要になる.これでは,せっかく継承を使っても, とても使いやすいとはいえない.また,リストの要素から値を取り出したり, また値をセットしたりする操作は,派生クラスごとに書き直さなければならない.

こんなときに便利な機能としてテンプレートがある.テンプレートを使って リストを書くと,こんな感じになる.

template <class T>
class List {
  protected:
    T nakami;
    List<T> *next;
  public:
    List(T& x, List<T>* n) { nakami = x; next = n; }
    ‾List() { delete n; }
    ....
};
template<class T>Tはパラメータで,これを実際に使う 時には,List<int>とかList<double>のように,<> の中に具体的な型が入る.テンプレートを記述しておくと,<> の中に入れた型ごとに,それぞれのクラスを記述したのと同じ効果を持つ. したがって,リストの中身ごとにクラスを派生させる必要はなく, 使った時点で自動的にクラスが生成される.なお,テンプレートは マクロと同じように作用するので,あらかじめコンパイルしておくことは できない.通常は,ヘッダファイルに記述される.

複数のファイルで,同じテンプレートから同じクラスを派生させたときに, テンプレートから生成されたメンバ関数の記述がどうコンパイルされるかは, コンパイラの実装に依存する.賢いコンパイラの場合,最終的に統合される ファイル全体を見て,おなじクラスは1回しか生成されないようにしてくれる. 賢くないコンパイラの場合,全く同じ関数がファイルごとに生成されるので, できた実行ファイルは無駄が多いものになってしまう.

なお,テンプレートでは,クラス名だけではなく,整数もパラメータに することができる.



Akinori ITO
Thu Aug 7 15:05:13 JST 1997