我对可克隆的抽象类和唯一指针有疑问。假设我有以下可克隆的抽象基类
class Base
{
public:
virtual void doSomething()=0;
virtual std::unique_ptr<Base> clone() const=0;
}
以及提供额外方法的派生抽象类
class Derived : public Base
{
public:
virtual void doSomething()=0;
virtual void doSomethingMore()=0;
virtual std::unique_ptr<Base> clone() const=0;
}
这允许定义通过组合存储 Base 层次结构的多态对象的新类。例如
class Composed
{
public:
Composed(Base const &base_) : basePtr(base_.clone()) {}
private:
std::unique_ptr<Base> basePtr;
}
通过这种方式,我应该能够在 Composed 中存储 Derived 类型的对象,而无需对 Derived 添加 wrt Base 的方法进行切片。但是,我想定义另一个对象来存储从 Derived 继承的多态对象,将其视为 Derived 类型的对象。使用与上面相同的结构
class ComposedDerived
{
public:
ComposedDerived(Derived const &derived_) : derivedPtr(derived_.clone()) {}
private:
std::unique_ptr<Derived> derivedPtr;
}
显然,由于 Derived 的 clone 方法返回一个
std::unique_ptr<Base>
,我收到了一个编译错误。另一方面,如果我改变 Derived 的定义如下class Derived : public Base
{
public:
virtual void doSomething()=0;
virtual void doSomethingMore()=0;
virtual std::unique_ptr<Derived> clone() const=0;
}
在这种情况下,编译器会给出以下错误:
invalid covariant return type for ‘virtual std::unique_ptr<Derived> Derived::clone() const
。有没有办法让编译器理解
std::unique_ptr<Derived>
实际上可以通过多态用作 std::unique_ptr<Base>
而不会争论派生类 clone
方法的返回类型? 最佳答案
对 clone()
方法使用 NVI(非虚拟接口(interface)习惯用法),如下所示:
class Base
{
public:
virtual void doSomething()=0;
std::unique_ptr<Base> clone() const {
return cloneImpl();
}
private:
virtual std::unique_ptr<Base> cloneImpl() const=0;
};
class Derived : public Base
{
public:
virtual void doSomething()=0;
virtual void doSomethingMore()=0;
std::unique_ptr<Derived> clone() const {
return std::unique_ptr<Derived>(static_cast<Derived*>(cloneImpl().release()));
}
};
您甚至可以在子类中添加“覆盖”
clone()
方法的更多安全性和便利性,如下所示:class Base
{
public:
virtual void doSomething()=0;
std::unique_ptr<Base> clone() const {
return checkedClone<Base>();
}
protected:
template<class T>
std::unique_ptr<T> checkedClone() const {
auto p = cloneImpl();
assert(typeid(*p) == typeid(*this) && "subclass doesn't properly override cloneImpl()");
assert(nullptr != dynamic_cast<T*>(p.get()));
return std::unique_ptr<T>(static_cast<T*>(p.release()));
}
private:
virtual std::unique_ptr<Base> cloneImpl() const=0;
};
class Derived : public Base
{
public:
virtual void doSomething()=0;
virtual void doSomethingMore()=0;
std::unique_ptr<Derived> clone() const {
return checkedClone<Derived>();
}
};
关于c++ - 可克隆的类层次结构和 unique_ptr,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37788255/