该克隆模式被用来做派生类的副本,而不拆毁到基类。 不幸的是, clone
必须在每个子类实现(或用CRTP一个mixin)。
是否有C ++ 11的任何机会decltype
使得这种不必要的?
我不认为低于实际复制的代码original
,只是指向它的引用。 当我试图用new decltype(*original)
,我得到一个错误: error: new cannot be applied to a reference type
。
是clone
还是走在C ++ 11的方式吗? 或者是有一些使用RTTI从基类指针复制一个派生类对象的新方式?
#include <iostream>
struct Base
{
virtual void print()
{
std::cout << "Base" << std::endl;
}
};
struct Derived : public Base
{
int val;
Derived() {val=0;}
Derived(int val_param): val(val_param) {}
virtual void print()
{
std::cout << "Derived " << val << std::endl;
}
};
int main() {
Base * original = new Derived(1);
original->print();
// copies by casting down to Base: you need to know the type of *original
Base * unworking_copy = new Base(*original);
unworking_copy->print();
decltype(*original) on_stack = *original;
on_stack.print();
return 0;
}
decltype
是一个静态结构。 像所有的C ++打字构建体,它不能推断对象的运行时类型。 decltype(*original)
只是Base&
。
decltype
(顾名思义)给出,它被施加到表达声明的类型(静态类型)。
decltype(*original)
为Base&
,所以你的代码将打印
Derived 1
Base
Derived 1
但没有副本将在第三种情况下进行。
克隆(或图案的一些变体)仍然在C ++ 11去的方式。
decltype
不能并且不恢复动态对象类型。 这是一个纯粹的静态结构。
没有什么神奇的方法来复制对象。 你必须某处调用其确切的最终动态类型的构造函数。
是克隆还是走在C ++ 11的方式吗? 或者是有一些使用RTTI从基类指针复制一个派生类对象的新方式?
如果有人有兴趣的非侵入性克隆,C ++ 11的lambda表达式似乎提供了一些新的克隆设施:关于克隆问题的思考,我就承认,谁制造的物体的原始实例的一个也应该是一个谁可以帮助建立一个副本。 假设在你所有的物体都是由一些制造的情况下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
也将得到清理。 不过,这应该只是被认为是实验证明的概念代码。