наследование — C ++ поддерживает смешанную коллекцию объектов подкласса

Извиняюсь, если мне здесь не хватает довольно фундаментальной концепции, но я пытаюсь выяснить, как поддерживать коллекцию из нескольких типов классов (все они происходят от одного и того же родителя) и при этом получать доступ к их методам, специфичным для подкласса. из коллекции.

В качестве контекста у меня есть один базовый класс («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», потому что он не знает, какой это тип подкласса.

Какой подход рекомендуется для такой ситуации? Должен ли я даже оказаться в ситуации, когда я «теряю» эту информацию о типе подкласса, добавляя в коллекцию тип BaseClass? Я не вижу другого способа сохранить коллекцию, но, пожалуйста, дайте мне знать о лучшей альтернативе.

Каждый объект SubClass содержит числовой идентификатор, который указывает, какой это подкласс; в результате, возможно ли написать функцию, которая преобразует этот числовой идентификатор в объект типа, который затем можно использовать для приведения исходного объекта перед вызовом конструктора копирования? Это допустимое использование для шаблонов?

Конечно, это может быть ужасной практикой программирования и / или невозможным. Я просто уверен, что должен быть лучший вариант, чем простое и наименее обслуживаемое решение

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

Решение

Вы можете определить абстрактные 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() { ... }

Это считается правильным переопределением, хотя тип возвращаемого значения отличается от базового класса.

Приведение указателей базового класса к производным классам на основе атрибута не считается хорошей практикой ООП.

3

Другие решения

Создайте новую функцию в ваших подклассах (возможно, сделайте ее чисто виртуальной в вашем базовом классе), которая будет выглядеть примерно так:

BaseClass * SubClassA::copy(){ /* Copy construtor like code. */ }

Это вызовет динамическое связывание, когда вы вызываете BaseClass-> copy () и вызываете конструктор копирования в SubClass.

2

По вопросам рекламы [email protected]