具有继承的元素的容器副本

时间:2012-06-27 21:07:04

标签: c++ qt

全部,这似乎是一个简单的问题,但它给了我适合。假设我有一个名为Animal的C ++基类,派生类Cat,Dog,Horse,Hippo,Snake。我有另一个名为Zoo的类,它包含一个Animal对象的列表(在这种情况下Qt List,其中基类Animal是QObject)。现在我要做的是创建一个Zoo对象,并能够将它复制到另一个Zoo对象,让目标Zoo拥有它自己的动物副本。问题出在Zoo复制构造函数中,因为它认为它有一个Animal列表,它调用Animal的拷贝构造函数而不是Dog,Cat等,因为编译器应该这样做。为了解决这个问题,我将Animal列表更改为Animal指针列表,然后创建了自己的Animal copy构造函数和赋值运算符。它们中的每一个都调用Animal :: Clone(Animal& rhs)方法,该方法又调用Animals Clone()方法的每个派生类,该方法返回从堆中分配的新指针及其数据副本。这一切都很好,但我一直在想,我错过了一个更优雅的解决方案。所以我的问题是,当你有一个包含类型对象的容器时,我们如何复制包含容器的类?我希望这是有道理的。

1 个答案:

答案 0 :(得分:2)

你所做的几乎是 在C ++中使用它的惯用方式。虚拟clone()方法实际上称为虚拟副本构造函数 idiom 。通常,您将其声明为以下签名的虚拟抽象方法。

Animal * clone() const = 0;

请注意,它不接受任何rhs参数,它只返回自身的克隆。给定动物Animal * myPet的实例,您可以通过说

来获得重复的动物
Animal * mySecondPet = myPet->clone();

如果要实例化它们,则必须在派生类中实现它。

[Ed:] 正如您所知,由于设计中固有的slicing problem,容器类不可能直接保存项而不是通过指针C ++。

在C ++中,你的解决方案是一个习惯用法:它的优雅与它一样优雅,每个看到它的人,谁知道他们的C ++,都应该立即知道你的意思。成语和某些设计模式是该语言的一部分。在不知道习语的情况下,你不能称自己精通语言,无论是人类还是编程语言。

在我的许多项目中,我使用一个名为Cloneable的接口类(所有抽象虚拟方法),它只包含此克隆方法。然后很容易强制某些基类可以克隆:只需从Cloneable继承。我希望QEventCloneable为例。实际上,不可能复制QEvents将它们发布到多个事件队列。

丹尼尔的建议“你有没有试过为Animal虚拟制作复制构造函数?”不能从字面上理解。在C ++中,实际上没有虚拟拷贝构造函数或任何构造函数这样的东西 - 原因很简单:在构造对象之前,它的虚方法表没有最终确定。具体来说,Animal的构造函数中的代码将在调用任何派生类的构造函数之前执行,以将虚方法表指针交换到派生类中的指针。因此,如果您在构造函数中进行了任何虚方法调用,则它们不会转到从您的类派生的任何类。就是这样。