如果我在这里遗漏了一个相当基本的概念,很抱歉,但我正在尝试解决如何维护多个类类型的集合(所有类型都派生自同一个父类),并且在从集合中检索它们时仍然可以访问它们特定于子类的方法。
作为上下文,我有一个基类("BaseClass")和许多类(比如"SubClassA“到"SubClassZ"),它们都派生自这个基类。我还需要维护所有SubClass对象的中央索引集合,我将其创建为
typedef unordered_map<std::string, BaseClass*> ItemCollectionType;
ItemCollectionType Items;list将只包含SubClass对象,但我已经将list成员类型定义为"BaseClass“指针,这样它就可以存储任何子类的实例。到目前为止,我假设这种方法没有什么特别糟糕的地方(但如果我错了,请纠正我)。
我的问题是,有时我需要创建这些集合及其内容的副本。我拥有的(简化的)代码如下:
ItemCollectionType CopiedItems;
ItemCollectionType::const_iterator it_end = Items.end();
for (ItemCollectionType::const_iterator it = Items.begin(); it != it_end; ++it)
{
BaseClass *src = it->second;
BaseClass *item = new BaseClass(src);
NewItems[item->code] = item;
}这里明显的问题是编译器只会调用BaseClass拷贝构造函数,而不是"src“实际指向的SubClass的拷贝构造函数,因为它不知道它是什么类型的SubClass。
对于这种情况,推荐的方法是什么?我是否应该因为添加到BaseClass类型的集合中而“丢失”这个子类类型信息呢?我看不到任何其他方法来维护收集,但请让我知道任何更好的替代方案。
每个SubClass对象都包含一个数字ID,该ID指示它是哪种类型的子类;因此,是否可以编写一个函数将该数字ID转换为“类型”对象,然后在调用复制构造函数之前使用该对象来转换源对象?这是模板的有效使用吗?
当然,这可能是糟糕的编程实践和/或不可能的。我确信应该有一个比最简单和最难维护的解决方案更好的选择
switch (src->code)
{
case SubClassTypes::VarietyA:
SubClassA *item = new SubClassA( *((SubClassA*)src) );
Items[item->code] = item;
break;
case SubClassTypes::VarietyB:
SubClassB *item = new SubClassB( *((SubClassB*)src) );
Items[item->code] = item;
break;
...
...
}发布于 2012-09-16 21:59:07
您可以定义将在每个子类中实现的抽象Clone方法。
virtual BaseClass* Clone() = 0;而不是简单地打电话:
for (ItemCollectionType::const_iterator it = Items.begin(); it != it_end; ++it)
{
BaseClass *src = it->second;
NewItems[item->code] = src->Clone();
}还要注意,C++支持返回值协方差,因此您的派生类可以返回确切的类型,而不仅仅是基类,例如
// in DerivedClass (which derives from BaseClass)
DerivedClass* Clone() { ... } 这被认为是一个适当的重写,尽管返回类型与基类中的不同。
基于属性将基类指针转换为指向派生类的指针不被认为是好的OOP实践。
发布于 2012-09-16 21:58:32
在你的子类中创建一个新的函数(也许在你的基类中使它成为纯虚的),这是类似于,
BaseClass * SubClassA::copy(){ /* Copy construtor like code. */ }当您调用BaseClass-> copy ()并调用SubClass上的复制构造函数时,这将调用动态绑定。
https://stackoverflow.com/questions/12447427
复制相似问题