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

Container copy of elements with inheritance

本文关键字:副本 元素 继承      更新时间:2023-10-16

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

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

Animal * clone() const = 0;

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

Animal * mySecondPet = myPet->clone();
如果要实例化派生类,

则必须在派生类中实现它。

[Ed:] 正如你所发现的,由于C++设计中固有的切片问题,容器类不可能直接而不是通过指针来保存项目。

在C++,你的解决方案是一个成语:它就像它得到的那样优雅,每个看到它的人,知道他们C++的人,都应该立即知道你的意思。习语和某些设计模式是语言的一部分。你不能称自己精通一种语言,无论是人类还是编程语言,而不了解习语。

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

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