続・ 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 を加味しつつ書いてやれば問題ないはず。