続・ interface と実装を分離する

http://d.hatena.ne.jp/janus_wel/20100608/1275986820 で一応 user に実装の詳細を見せなくすることができたわけだけど user 側で delete 文を使う必要が出てきてしまったわけだ。というわけでそこらへんを何とかしようというのが目的。でまぁ早速なんだけど以下のようにすれば無問題だということに std::use_facet を見ていて気付いた。

// interface.hpp

#ifndef INTERFACE_HPP
#define INTERFACE_HPP

#include <string>

namespace sample {
    struct interface_type {
        virtual void print(void) const = 0;
        virtual void set(const std::string& str) = 0;
    };

    // Returning reference
    interface_type& use(void);
}

#endif // INTERFACE_HPP
// implement.cpp

#include "interface.hpp"

#include <iostream>

namespace sample {
    namespace implement {
        class concrete_type : public interface_type {
            private:
                std::string mv_str;

            public:
                concrete_type(void) : mv_str("concrete") {
                    std::cout << "concrete_type()" << std::endl;
                }
                ~concrete_type(void) {
                    std::cout << "~concrete_type()" << std::endl;
                }
                void print(void) const {
                    std::cout << mv_str << std::endl;
                }
                void set(const std::string& str) {
                    mv_str = str;
                }
        };
    }

    interface_type& use(void) {
        static implement::concrete_type concrete;
        return concrete;
    }
}

こんな感じで sample::use() 関数 ( http://d.hatena.ne.jp/janus_wel/20100608/1275986820 では sample::create() 関数にあたる。 object を生成するというよりはすでにある object を使う感覚なので個人的にこの関数名のほうがしっくりきた ) 内に static object を作ってそいつへの参照を返す、という形にする。

// main.cpp

#include "interface.hpp"

using namespace sample;

int main(void) {
    interface_type& i = use();
    i.set("zero-one");
    i.print();

    return 0;
}

で、 user 側では上記のように sample::use() 関数の戻り値を参照で受ける。ここらへんは例外処理の catch 節と一緒で参照だと slicing をおこさずに object を受け渡しできるからだね。

というわけで delete を意識する必要をなくすることができたわけだ。いやでも static て program 終了まで object が生きているわけで空間効率的にどうなのよ ? ていうアレもないことはないんだけどそれは sample::use() 関数の代わりに object の生成と貸し出しを行う member function と object の破棄を行う member function を持つ class を singleton pattern と factory pattern を加味しつつ書いてやれば問題ないはず。