C ++ clone习语中协变返回类型的用处?

时间:2010-11-16 22:10:52

标签: c++ idioms

通常的克隆习语使用协变返回类型:

struct Base {
    virtual Base* clone();
};

struct Derived : public Base {
    Derived* clone();
};

我已经读过这样的信息,即协变返回类型是C ++的后续添加,而较旧的编译器可能不支持它们。在这种情况下,Derived类必须声明其clone成员函数以返回Base*。因为,据推测,我只是在使用这个成语时通过Derived指针和/或引用访问Base个对象,声明返回类型Derived*的真正用途/好处是什么? / p>

另外,一个相关问题:

我更喜欢使用智能指针来表达clone签名的所有权转移语义。使用协变返回类型时,这是不可能的,因为auto_ptr<Derived>auto_ptr<Base>不协变。 (请注意,我不是在寻找关于智能指针使用的讲座 - auto_ptr仅用作示例)。那么在这种情况下,有没有理由不让Derived返回auto_ptr<Base>?是否有更好的方式来表达所有权转移语义?

2 个答案:

答案 0 :(得分:3)

  

因为,据推测,我只是在使用这个成语时通过Base指针和/或引用来访问Derived对象...

你认为错了。仅仅因为Base类存在并不意味着你将永远使用它。如果我有一个Shape类包含子类CircleRectangle,我也有一个Window类。当我可以使用Shape*时,我不打算使用Rectangle作为窗口的位置和大小。

对于所有权转让,无论如何都不应该使用智能指针。我知道你不想讲课,但我不是说智能指针很糟糕,你不应该在clone()中使用它们。您不能首先转让没有所有权的东西的所有权。如果有人想要auto_ptr,那么他们应该使用克隆的原始指针构造它。其他智能指针类型也是如此。

答案 1 :(得分:2)

当你有一个指向Derived并希望得到它的克隆时,这很有用:

Derived *ptr = ...;
Derived *clone = ptr->clone();

没有协变返回类型,您必须进行显式转换:

Derived *clone2 = (Derived*)ptr->clone();

请注意,Derived可能是更多派生类的基类,在这种情况下它更有意义。

不幸的是,auto_ptr<Derived>auto_ptr<Base>不是协变的。因此,在这种情况下,您必须从所有克隆函数返回相同的类型。