道歉,如果我在这里缺少一个相当基本的概念,但我正在尝试研究如何维护多个类类型的集合(所有类都派生自相同的父类),并且仍然可以访问其子类特定的方法从集合中检索它们时。
作为上下文,我有一个基类(“BaseClass”)和许多类(比如“SubClassA”到“SubClassZ”),它们都来自这个基类。我还需要维护所有SubClass对象的集中索引集合,我将其创建为
typedef unordered_map<std::string, BaseClass*> ItemCollectionType;
ItemCollectionType Items;
该列表将只包含SubClass对象,但我已将列表成员类型定义为“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转换为“类型”对象的函数,然后可以在调用复制构造函数之前将其用于转换源对象?这是模板化的有效用途吗?
当然,这可能是糟糕的编程习惯和/或不可能。我确信应该有比
最简单,维护最少的解决方案更好的选择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;
...
...
}
答案 0 :(得分:3)
您可以定义将在每个子类中实现的抽象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实践。
答案 1 :(得分:2)
在你的子类中创建一个新函数(也许在你的基类中使它成为纯虚函数),这是一个类似的东西,
BaseClass * SubClassA::copy(){ /* Copy construtor like code. */ }
当您调用BaseClass-&gt; copy()并在SubClass上调用复制构造函数时,这将调用动态绑定。