C ++维护子类对象的混合集合

时间:2012-09-16 13:54:58

标签: c++ inheritance collections copy-constructor derived-class

道歉,如果我在这里缺少一个相当基本的概念,但我正在尝试研究如何维护多个类类型的集合(所有类都派生自相同的父类),并且仍然可以访问其子类特定的方法从集合中检索它们时。

作为上下文,我有一个基类(“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;
    ...
    ...
}

2 个答案:

答案 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上调用复制构造函数时,这将调用动态绑定。