Entry

プログラミングメモ - boost::any を読む

2009年02月27日

昨日力尽きて書けなかった boost::any の実装話。

Boost C++ library は,C++ の便利クラスを集めたライブラリです。リリースされてから随分経つので,ご存知の方も多いはず。その中にある,boost::any クラスは,「any 型」というどんな型でも放り込める型を提供してくれる夢のようなクラスです。

使い方については,丁寧な説明を作ってくださっている方がたくさんいらっしゃるので,ぐぐってみてください。ここでは中身の話だけ。C++ でどうやって「なんでも型」を作っているのか見てみます。先に言ってしまうけれど,この設計は美しいと思う。

つことで,ソースコードです。キャスト周りや周辺のおまけメソッドは省略。体裁を修正しています。

class any {
public: // structors
    any() : content(0) {
    }
    template<typename ValueType>
    any(const ValueType & value)
        : content(new holder<ValueType>(value)) {
    }
    any(const any & other)
        : content(other.content ? other.content->clone() : 0) {
    }
    ~any() {
        delete content;
    }
public: // modifiers
    any & swap(any & rhs) {
        std::swap(content, rhs.content);
        return *this;
    }
    template<typename ValueType>
    any & operator=(const ValueType & rhs) {
        any(rhs).swap(*this);
        return *this;
    }
    any & operator=(const any & rhs) {
        any(rhs).swap(*this);
        return *this;
    }
private:
    class placeholder {
    public: // structors
        virtual ~placeholder() {
        }
    public: // queries
        virtual placeholder * clone() const = 0;
    };
    
    template<typename ValueType>
    class holder : public placeholder {
    public: // structors
        holder(const ValueType & value) : held(value) {
        }
    public: // queries
        virtual placeholder * clone() const {
            return new holder(held);
        }
    public: // representation
        ValueType held;
    };

    placeholder * content;
};

ソースだけじゃちと分かりにくいので,UML のクラス図モドキを描いてみました。描くのに使った Dia じゃ inner class やコンポジションを描けないので,雰囲気だけ。

20090227_boost_any.png

C++ にインターフェイスの概念はないんですけれど,placeholder クラスは,全部が純粋仮想関数なので,Java や C# にいわゆるインターフェイスです。ポイントの1点目はこの点で,本体である any::content メンバが,この placeholder インターフェイスへのポインタを持っているところです。一方,コードを見れば分かる通り,この実体は,それを継承した holder クラステンプレートのオブジェクトです。つまり,この仕組みがあるおかげで,テンプレートから特化した holder クラスがどんな型で実体化されても,placeholder インターフェイスを通じて実体にアクセスすることができるというわけ。

インターフェイスというと,複数の異なるクラスに共通のインターフェイスを持たせることで,ポリモーフィズムを可能にすることが強調されるけれど,全く異なるクラスである必要はなくて,テンプレートのようなもんでもいい。言ってみれば template → interface と2段階で抽象化しているわけで,これは上手いなあと思う。

一方,この holder クラスの初期化はどうするのかというと,オペレータやコピーコンストラクタをテンプレート関数として定義することで実現しています。これがポイント2点目。これでどんな型でも受け入れられるし,どんなオブジェクトも内部に持つことができる。上述のインターフェイスのおかげで,アクセスもできる。すげいなあ。

あと,C++ で任意の型を扱う場合,最後に残る難所が,placeholder クラスからのダウンキャストです。C++ のプログラマさんの一部には,ダウンキャストするやつは腹切って死ね!という人もいるわけですけれど(いないか),こればっかりはしょうがない。boost::any の場合もダウンキャストはするわけですけれど,例外周りを固めているので腹切るまではしなくて済みそうです。よく分からんけど。

ともあれ,この設計はクラスによる抽象化のお手本みたいな設計なんだと思います。いいもん見せてもらいました。

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