squirrel_code @ ウィキ
template × mix-in
最終更新:
squirrel_code
-
view
template × mix-in
last update: 2010/12/28 (Tue)
さて,この記事のテーマとは template と mix-in でどちらが攻○でどちらが受○か,ではない!
なんてタイトルをつけやがる….期待させて申し訳ないが(絶対違う)Mix-in とは,継承を用いて既存のクラスに機能を後付けしたいときに使う.簡単なコードは以下の通り.
// mixin.h
#include <list> // for std::list
#include <algorithm> // for std::find
// コンテナに格納されるクラス
class A { /* 省略 */ }
// コンテナ機能を付加する Mix-in
class MixIn
{
std::list<A> as;
public:
MixIn() {}
virtual ~MixIn() {}
void add(A* a);
void remove(A* a);
};
// Mix-in されるクラス
class Container : public MixIn
{
public:
Container() : MixIn() {}
~Container() {}
};
// mixin.cpp
#include "mixin.h"
// MixIn の実装
void MixIn::add(A* a)
{ as.push_back(a); }
void MixIn::remove(A* a);
{
typedef std::list<A>::iterator iter;
iter i = std::find(as.begin(), as.end(), a);
if (i != as.end()) as.erase(i++);
}
コンテナのデストラクタの実装はサボり^^.こんな感じで,Container クラスに後付けでクラス A のコンテナ機能を付加できる.
Mix-in が便利なのは,複数の Mix-in を用意して,それをがんがん後付けしていけること.試しにクラス B のコンテナ機能も付加してみる.
その1
// mixin.h
#include <list> // for std::list
#include <algorithm> // for std::find
// コンテナに格納されるクラス
class A { /* 省略 */ }
class B { /* 省略 */ }
// A のコンテナ機能を付加する Mix-in
class MixInA
{
std::list<A> as;
public:
MixInA() {}
virtual ~MixInA() {}
void add(A* a);
void remove(A* a);
};
// B のコンテナ機能を付加する Mix-in
class MixInB
{
std::list<B> bs;
public:
MixInB() {}
virtual ~MixInB() {}
void add(B* b);
void remove(B* b);
};
// Mix-in されるクラス
class Container : public MixInA, public MixInB
{
public:
Container() : MixInA(), MixInB() {}
~Container() {}
};
// mixin.cpp
#include "mixin.h"
// MixInA の実装
void MixInA::add(A* a)
{ as.push_back(a); }
void MixInA::remove(A* a);
{
typedef std::list<A>::iterator iter;
iter i = std::find(as.begin(), as.end(), a);
if (i != as.end()) as.erase(i++);
}
// MixInB の実装
void MixInB::add(B* b)
{ bs.push_back(b); }
void MixInB::remove(B* b);
{
typedef std::list<B>::iterator iter;
iter i = std::find(bs.begin(), bs.end(), b);
if (i != bs.end()) bs.erase(i++);
}
main 関数から Cointainer::add を呼んでやって,これを gcc でコンパイルすると
error: request for member add is ambiguous
と怒られる. MixInA から継承した add(A* a) と MixInB から継承した add(B* a) では引数の型が違うのにもかかわらず,自動ではオーバーロードされない.これは template を用いた mix-in でも同じで,最後に Mix-in したメソッド以外は名前修飾してやらないとメソッドが見つからないというエラーになる.
pImpl × 継承 の(その2)でもメソッドのオーバーライドをしているが,やはり C++ で実装の再利用に public 継承を用いてはいけないのである(たぶん). C++ の教義に従えば,ここは Mix-in を private 継承し, Container 内でそれを呼ぶのがスマートである(ような気がする).
その2
// mixin.h
#include <list> // for std::list
#include <algorithm> // for std::find
// コンテナに格納されるクラス
class A { /* 省略 */ }
class B { /* 省略 */ }
// A のコンテナ機能を付加する Mix-in
class MixInA
{
std::list<A> as;
public:
MixInA() {}
~MixInA() {}
void add(A* a);
void remove(A* a);
};
// B のコンテナ機能を付加する Mix-in
class MixInB
{
std::list<B> bs;
public:
MixInB() {}
~MixInB() {}
void add(B* b);
void remove(B* b);
};
// Mix-in されるクラス
class Container : private MixInA, private MixInB
{
public:
Container() : MixInA(), MixInB() {}
~Container() {}
// MixInA の呼び出し
void add(A* a)
{ MixInA::add(a); }
void remove(A* a)
{ MixInA::remove(a); }
// MixInB の呼び出し
void add(B* b)
{ MixInB::add(b); }
void remove(B* a)
{ MixInB::remove(b); }
};
// mixin.cpp
#include "mixin.h"
// MixInA の実装
void MixInA::add(A* a)
{ as.push_back(a); }
void MixInA::remove(A* a);
{
typedef std::list<A>::iterator iter;
iter i = std::find(as.begin(), as.end(), a);
if (i != as.end()) as.erase(i++);
}
// MixInB の実装
void MixInB::add(B* b)
{ bs.push_back(b); }
void MixInB::remove(B* b);
{
typedef std::list<B>::iterator iter;
iter i = std::find(bs.begin(), bs.end(), b);
if (i != bs.end()) bs.erase(i++);
}
Mix-in クラスはもはや public 継承されないので,デストラクタの virtual は外している.
しかし面倒な.なんとかならんものか...
&trackback()
参考
コメント
- コメントの投稿テスト -- (tossy_squirrel) 2010-12-29 03:35:18