clone范例用于制作派生类的副本,而不会转换为基类类型。不幸的是,clone
必须在每个子类中实现(或者使用带有CRTP的mixin)。
C ++ 11 decltype
是否有可能使这个不必要?
我不认为下面的代码实际上会复制original
,而只是指向它的引用。当我尝试使用new decltype(*original)
时,出现错误:
error: new cannot be applied to a reference type
。
{+ 1}}仍然是C ++ 11的发展方向吗?或者是否有一些新方法使用RTTI从基类指针复制派生类对象?
clone
答案 0 :(得分:21)
decltype
是一个静态构造。与所有C ++类型构造一样,它不能推断出对象的运行时类型。 decltype(*original)
只是Base&
。
答案 1 :(得分:3)
decltype
(顾名思义)给出了应用它的表达式的声明的类型(静态类型)。
decltype(*original)
为Base&
,因此您的代码将打印
Derived 1
Base
Derived 1
但在第三种情况下不会复制。
克隆(或模式的某些变体)仍然是C ++ 11中的方法。
答案 2 :(得分:3)
decltype
无法恢复动态对象类型,也无法恢复。它是一个纯粹的静态构造。
复制对象没有神奇的方法。您必须调用其确切的最终动态类型某处的构造函数。
答案 3 :(得分:2)
克隆仍然是C ++ 11的发展方向吗?或者是否有一些新方法使用RTTI从基类指针复制派生类对象?
如果有人对非侵入式克隆感兴趣,C ++ 11的lambdas似乎提供了一些新的克隆设施:考虑克隆问题,我开始承认制造了一个对象的原始实例的人也应该是可以帮助构建副本的人。考虑所有对象都由某些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
方法中构造的(通过将指向对象的指针与将调用复制构造函数的lambda相关联)。永远不要丢弃旧蓝图,以后可能需要它们; - )
坦率地说,我仍然更喜欢使用CRTP等旧的clone
解决方案,但这可能会引发一些新的想法或者其他方便使用。
上面的代码也在http://ideone.com/kIPFt2
编辑:正如wjl所评论的那样,代码的第一个版本会导致cloneFnMap
稳步增长。在考虑完之后,我决定通过向返回的shared_ptr
引入自定义删除器来修复代码,以便cloneFnMap
也将被清除。不过,这应该只是一个实验性的概念证明代码。