クローンはまだC++11に行く方法ですか?または、RTTIを使用して基本クラスポインタから派生クラスオブジェクトをコピーする新しい方法はありますか?
非侵襲的なクローン作成に興味がある人のために、C ++ 11のラムダはいくつかの新しいクローン作成機能を提供しているようです。クローン作成の問題を考えると、オブジェクトの元のインスタンスを作成した人もレプリカの作成を支援できる人。すべてのオブジェクトが一部のによって製造されている場合を考えてみますFactory
。この場合、通常のcreate
インターフェースに加えて、工場にインターフェースを装備することができclone
ます。たとえば、次のようになります。
#include <iostream>
#include <functional>
#include <memory>
#include <unordered_map>
template <typename BASE>
struct
Factory {
private: using
TCloneFn = std::function<std::shared_ptr<BASE>(BASE const * const)>;
private:
static std::unordered_map<BASE const*,TCloneFn> cloneFnMap;
public: template <typename DERIVED_TYPE, typename...TS>
static std::shared_ptr<BASE>
create(TS...args) {
BASE* obj = new DERIVED_TYPE(args...);
const std::shared_ptr<BASE> pNewObj =
std::shared_ptr<BASE>(
obj,
[&](BASE* p){
cloneFnMap.erase(p);
delete p;
}
);
cloneFnMap[obj] = [&](BASE const * const orig){
std::shared_ptr<BASE> pClone = create<DERIVED_TYPE>(std::ref(static_cast<DERIVED_TYPE const &>(*orig)));
return pClone;
};
return pNewObj;
}
public: static std::shared_ptr<BASE>
clone(std::shared_ptr<BASE const> original) {
return cloneFnMap[original.get()](original.get());
}
};
template <typename BASE> std::unordered_map<BASE const*,typename Factory<BASE>::TCloneFn> Factory<BASE>::cloneFnMap;
class Base {
public: virtual ~Base() throw() {}
public: virtual void whoAmI() const {
std::cout << "I am Base instance " << this << "\n";
}
};
class Derived : public Base {
std::string name;
public: Derived(std::string name) : name(name) {}
public: Derived(const Derived&other) : name("copy of "+other.name) {
}
private: virtual void whoAmI() const {
std::cout << "I am Derived instance " << this << " " << name << "\n";
}
};
int main() {
std::shared_ptr<Base> a = Factory<Base>::create<Derived>("Original");
a->whoAmI();
std::shared_ptr<Base> copy_of_a = Factory<Base>::clone(a);
copy_of_a->whoAmI();
std::shared_ptr<Base> copy_of_a_copy = Factory<Base>::clone(copy_of_a);
copy_of_a_copy->whoAmI();
return 0;
}
秘訣は、オリジナルがメソッドでどのように構築されたかを覚えておくことですFactory::create
(オブジェクトへのポインターを、コピーコンストラクターを呼び出すラムダに関連付けることによって)。古い設計図を捨てないでください。後で必要になる場合があります;-)
率直に言って、私はまだclone
CRTPなどの古いソリューションを好みますが、これはいくつかの新しいアイデアを引き起こすか、そうでなければ便利になるかもしれません。
上記のコードはhttp://ideone.com/kIPFt2にもあります
編集: wjlがコメントしたように、コードの最初のバージョンはcloneFnMap
着実に成長するでしょう。よく考えた後、shared_ptr
返されるsにカスタム削除機能を導入してコードを修正し、cloneFnMap
もクリーンアップされるようにすることにしました。それでも、これは実験的な概念実証コードと見なす必要があります。