Niftyの過去ログ集 - RTTI Visitor
RTTI Visitor
Visitor パターンの面白い応用例として,RTTI Visitor というのがあります.RTTI,つまり実行時型情報を取得するのに Vistor を使ったものです.
02869/02869 BYI20012 まさーる RTTI Visitor
( 6) 99/04/13 01:02 02864へのコメント
真亜機伊 さん,こんにちは.
>社内の部品を使っていた当時はダウンキャストは一歩間違うと危
>険だなあと思っていました.(当時,安全にダウンキャストする
>仕組みは,その処理系にはありませんでした.)
ちょっと話がそれますが,こういう状況でdynamic_castをシュミレートするため
にRTTI Visitorパターンというものがあります.Visitorパターンの可能性を知
る上でいいんじゃないでしょうか.
RTTI Visitorは
"Design Patterns for Dual Inheritance Hierarchies in C++"
Robert C. Martin
(http://www.oma.com/Publications/publications.htmlから入手可)
で解説されています.
このアーティクルから,サンプルコードを引用します:
class BVisitor;
class D1;
class D2;
class B
{
public:
virtual void Visit(BVisitor&) = 0;
};
class BVisitor
{
public:
BVisitor() : itsD1(0), itsD2(0) {}
void Visit(D1& d1) {itsD1 = &d1;}
void Visit(D2& d2) {itsD2 = &d2;}
D1* GetD1() const {return itsD1;}
D2* GetD2() const {return itsD2;}
private:
D1* itsD1;
D2* itsD2;
};
class D1 : public B
{
public:
virtual void Visit(BVisitor& bv)
{bv.Visit(*this);} // class Visit(D1&)
};
class D2 : public B
{
public:
virtual void Visit(BVisitor& bv)
{bv.Visit(*this);} // class Visit(D2&)
};
// Global functions
D1* dynamic_cast_D1(B* b)
{
BVisitor v;
b->Visit(v);
return v.GetD1();
}
D2* dynamic_cast_D2(B* b)
{
BVisitor v;
b->Visit(v);
return v.GetD2();
}
いやー,こんなのよく思いつきますね,感心します.
99/04/13(火) まさーる(BYI20012)
ちょっとわかりにくいかもしれませんが,最後にある dynamic_cast_D1 に D1 オブジェクトのポインタを引数として渡すと D1 ポインタが, D2 オブジェクトのポインタを渡すと NULL が返ってくることがわかると思います.今流行のテストケースで書いてみるとこんな感じでしょうか:
D1 d1;
D2 d2;
void test_dynamic_cast_D1()
{
assertEquals(&d1, dynamic_caset_D1(&d1));
assertEquals( 0, dynamic_caset_D1(&d2));
}
void test_dynamic_cast_D2()
{
assertEquals( 0, dynamic_caset_D2(&d1));
assertEquals(&d2, dynamic_caset_D2(&d2));
}
(CppUnit は使ったことがないので適当です.void* へキャストが必要かも)
もちろん,Visitor パターンなので Visitor パターンの問題点(新しい B のサブクラスを追加するという仕様変更に弱い)をそのまま受け継いでいます^^;.
参考資料
- Design Patterns for Dual Inheritance Hierarchies in C++ , Robert C. Martin, C++ Report, April, 1997
