Entry

プログラミングメモ - テンプレートと継承を使ったハンドラみたいなもの

2010年04月02日

ちょっと実験。本当に個人的なメモなので,分かりにくかったらごめんなさい。

#include <iostream>

////////////////////////////////////////////////////////////
// 基底クラス(テンプレート)
template<typename T>
class Base {
public:
  Base() throw ();
  virtual ~Base() throw ();
public:
  virtual void func(T n) const throw () = 0;
};

template<typename T>
Base<T>::Base() throw () {
}

template<typename T>
Base<T>::~Base() throw () {
}

////////////////////////////////////////////////////////////
// 派生クラス
// (int 型でインスタンス化したテンプレートクラスから派生)
class Derived : public Base<int> {
public:
  Derived() throw ();
  virtual ~Derived() throw ();
public:
  virtual void func(int n) const throw ();
};

Derived::Derived() throw () {
}

Derived::~Derived() throw () {
}

void
Derived::func(int n) const throw () {
  std::cout << n << ": Base<int>" << std::endl;
}

////////////////////////////////////////////////////////////
// クライアントとなるクラス
class SomeClass {
public:
  SomeClass() throw ();
  virtual ~SomeClass() throw ();
public:
  template<typename T> void someFunc(const Base<T>& d);
};

SomeClass::SomeClass() throw () {
}

SomeClass::~SomeClass() throw () {
}

// Base<T> 型のクラスを受け取るが,どの型でインスタンス化して
// いるかは知らなくていい
template<typename T>
void SomeClass::someFunc(const Base<T>& d) {
  d.func(T());
}


////////////////////////////////////////////////////////////
int
main(int argc, char* argv[]) {
  Derived derived;
  // テンプレート関数呼び出し
  SomeClass someClass;
  someClass.someFunc(derived);
  return 0;
}

えーと……やりたいことはどういうことかというと,main 関数を見てもらうと分かるかもしれません。SomeClass の関数 someFunc に Derived クラスのオブジェクト derived を渡して,呼び先で derived のメソッドを実行するというものです。

ミソはどこかというと,someFunc がテンプレート関数になっていて,Base<T> 型のオブジェクトを渡している点です。Base<T> クラスというのは,抽象クラス(純粋仮想関数を持っているクラス)で,インターフェイスの存在を保証するだけのクラスです。実際の実装は,これを任意の型(int)で継承した Derived というクラスで行っています。一方,関数 SomeClass::SomeFunc はテンプレートとして受け取っているので,この関数を書いている時点では,受け取るオブジェクトがどの型でインスタンス化されているのか,知る必要はありません。ここがミソ。

Derived と同じように,別のクラスを作って Base<T> クラスから派生させれば,使用している型について意識せずに SomeClass::someFunc に渡すことができる。

なんでこういうことをしたいのか,話せば長くなるので端折っちゃうと,あるクラスの挙動をハンドルするクラスを定義したかったからです。「あるクラス」というのは,ここでいう SomeClass のこと。ハンドルするクラスというのは Derived のことです。SomeClass のハンドルの仕方が何通りかあって,ハンドルの仕方によって扱う型も異なる場合があったりします。もっと具体的に言うと,画像を読み込むときの話。1ピクセル1バイトの幅でグレイスケールに変換しつつ読み込むとか,1ピクセルを Windows で使われる RGBQUAD のような構造体に収めるように読み込むとかいうように,何種類か読み込み方があって,それを統一的に扱いたいんです。

で,こゆことをするには,機能を3つくらいに分ける必要があります。ひとつは,画像そのものを収めるクラス。もうひとつは,画像を読み込むクラス。最後は,読み込んだ画素を最初のクラスに収まるように調整するクラスです。そしてそれぞれのクラスについて,型に対する抽象性を持たせることで,ユーザは任意の組み合わせで,画像を読み込むことができるというわけです。

テンプレートを使ったプログラムの設計は,いまだに頭の中だけでできないところがあって,実際にモックアップを作らないと自信が持てなかったりします。今回は割といい感じにまとまりそう。この調子で画像を扱うライブラリを作ることにします。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN