C++ 协变收益类型在C++;克隆成语?

C++ 协变收益类型在C++;克隆成语?,c++,idioms,C++,Idioms,通常的克隆习惯用法使用协变返回类型: struct Base { virtual Base* clone(); }; struct Derived : public Base { Derived* clone(); }; 我读到一些东西,协变返回类型是后来添加到C++中的,旧编译器可能不支持它们。在这种情况下,派生的类必须声明其克隆成员函数以返回一个基*。既然在使用这个习惯用法时,我大概只通过Base指针和/或引用访问Derived对象,那么声明返回类型Derived*的真正

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

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

struct Derived : public Base {
    Derived* clone();
};
<>我读到一些东西,协变返回类型是后来添加到C++中的,旧编译器可能不支持它们。在这种情况下,
派生的
类必须声明其
克隆
成员函数以返回一个
基*
。既然在使用这个习惯用法时,我大概只通过
Base
指针和/或引用访问
Derived
对象,那么声明返回类型
Derived*
的真正用途/好处是什么

还有一个相关问题:

我更愿意使用智能指针来表示
clone
签名的所有权转移语义。这在使用协变返回类型时是不可能的,因为
auto_ptr
auto_ptr
不协变。(请注意,我不是在找关于智能指针使用的讲座--
auto_ptr
只是这里的一个例子)。那么在这种情况下,是否有任何理由不让
派生
返回
自动ptr
?有没有更好的方式来表达所有权转移语义

因为,大概在使用这个习惯用法时,我只通过基指针和/或引用访问派生对象

你想错了。基类的存在并不意味着您将一直使用它。如果我有一个
形状
类和子类
圆形
矩形
,我还有一个
窗口
类。我不会使用
形状*
作为窗口的位置和大小,而只使用
矩形


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

当您有一个指向派生的
的指针,并且希望获得它的克隆时,它非常有用:

Derived *ptr = ...;
Derived *clone = ptr->clone();
如果没有协变返回类型,则必须执行显式强制转换:

Derived *clone2 = (Derived*)ptr->clone();
请注意,
Derived
可能是更多派生类的基类,在这种情况下,它更有意义


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

您应该看看这里:我想知道“通常的克隆习惯用法使用协变返回类型”的说法。我个人认为这是一个麻烦。@John--这是一个麻烦吗?@ybungalobill:最后一句中的结论不正确,虽然智能指针不是协变(每个C++规则)是正确的。模拟协方差很简单。例如,在C++中实现可重用克隆功能。cheers,@Alf博客文章摘要-有一个返回指针的虚拟函数(用协变返回类型重写),和一个返回智能指针的公共非虚拟函数(在每个派生类中重载)。这样,调用者总是获得与调用函数时使用的静态类型对应的智能指针。在Alf的例子中,虚拟函数是受保护的,尽管我不知道为什么它不是私有的。@Steve:我同意
private
可能会更好,但是我不确定是否从克隆返回智能指针,主要是因为它没有遵循Boost的
Clonable
概念。@Alf:是的,我知道。我自己也使用这种技术。@Matthieu:我认为这没关系-如果您想实现
Clonable
,请添加一个调用虚拟函数的无好友函数
new\u clone
。返回智能指针符合这样一种风格,即
auto_ptr
返回值用于“记录”新资源的所有权,如果调用方希望使用任何其他智能指针类型,则它们
release()
。我更喜欢返回指针,并让调用者负责将其放入他们选择的智能指针中,使用C++0x,它将始终是
唯一的\u ptr
,而不是
自动的\u ptr
,因此所讨论的样式应该改变。“当我可以使用矩形时”-那是你的错我所有的窗户都是长方形的?使用
形状*
!那么在这种情况下,我认为你已经在有毒设计的海洋中游泳了。另外,我不确定你关于“不应该在克隆中使用[smart pointers]”的论点是否真的成立。它和任何所有权转移场景一样有效,不是吗?
clone
函数创建(并因此拥有)新对象,直到它返回给调用者。@Tabber:任务没有理想的智能指针,只有
unique_ptr
具有所需的语义,但这需要一个符合C++0x的编译器(移动语义)
auto_ptr
最好尽可能不使用,其他类型的智能指针会带来不必要的开销。@Tabber33:真的吗?你认为界面的层次结构是“有毒的设计”?如果是这样的话,为什么不完成这个想法,并停止使用动态多态性呢?@Steve:当然不是——只是在OO是有毒设计的情况下。对我来说,这听起来像是“我会直接使用派生类,因为我碰巧能够,而我真的应该使用适当的接口类。”但我理解有时需要直接访问派生类,这就是协变返回类型有用的地方(在克隆后保存向下转换)。