我遇到了克隆抽象类和唯一指针的问题。假设我有以下可克隆的抽象基类
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的克隆方法返回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
方法的返回类型?
答案 0 :(得分:2)
对clone()
方法使用NVI(非虚拟接口惯用法),如下所示:
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>();
}
};
答案 1 :(得分:1)
如何利用协变回报:
class Base {
public:
std::unique_ptr<Base> clone() const {
return std::unique_ptr<Base>(cloneImpl());
}
virtual ~Base();
private:
virtual Base* cloneImpl() const;
};
class Derived : public Base {
public:
std::unique_ptr<Derived> clone() const {
return std::unique_ptr<Derived>(cloneImpl());
}
~Derived() override;
private:
// Covariant return:
Derived* cloneImpl() const override;
};