interface と実装を分離する

例えば何らかの domain に特化した class なり function なりを詰め込んだ library ( static / dynamic 問わず ) もしくは obj やら o やらとそれを使うための interface である header file 、というようなものを作るとき、 C++ で素直にやるなら継承を使って以下のような形にすることが多いと思う。

// 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;
        virtual ~interface_type(void) {}
    };

    // Returning pointer
    interface_type* create(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* create(void) {
        return new implement::concrete_type();
    }
}

という 2 つの file を書いて例えば以下のように compile 。

  • VC++
    • cl /EHsc /W4 /c implement.cpp
  • g++
    • g++ -Wall --pedantic -c implement.cpp

で、できた o もしくは obj file を interface.hpp と一緒に user に渡す、と。

// main.cpp

#include "interface.hpp"

#include <memory>

using namespace sample;

int main(void) {
    std::auto_ptr<interface_type> i(create());
    i->set("mutable");
    i->print();

    return 0;
}

user 側はこういう感じで使いつつ以下のような感じで compile 。

  • VC++
    • cl /EHsc /W4 main.cpp implement.obj
  • g++
    • g++ -Wall --pedantic main.cpp implement.obj

こうすることで user は interface だけ相手にすればいい状況を作ることができる。んだけど sample::create() 関数が返す object を user が delete しなければならない ( ここでは std::auto_ptr を使って delete をいちいち書かなくていいようにしてるけど ) という制約が発生する。めんどくさいのでこれを何とかしたい。というところで一回切る。