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