我对可克隆的抽象类和唯一指针有疑问。假设我有以下可克隆的抽象基类

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/

10-11 22:42
查看更多