До сих пор я использовал динамическое приведение. Но это имеет свои плюсы и минусы. Кажется, это хорошая вещь, НЕ использовать это слишком много. Примеры по этой теме, которые я нашел, обычно с классами, которые имеют небольшие различия. Но в моем случае у «детских» классов очень мало общего.
Код в этом посте НЕ из проекта. Он используется только для примера.
Я делаю торговую систему для игры, и в проекте будет еще много систем. Есть много разных предметов, которые делают много разных вещей — оборудование, модификации, ресурсы. Независимо от того, насколько они различны, у всех них есть цена, и все они могут быть помещены в инвентарь, независимо от того, что они. Но на этом сходство заканчивается, включая переопределенные методы.
После этого разные предметы используются совершенно по-разному. Сначала разные типы предметов сортировались в отдельных массивах указателей разных типов — один для оборудования, один для модификаций, например, т. Д. Чтобы положить что-то в инвентарь, я использую только один метод: addToInventory(Item* item)
, Поскольку элемент должен быть помещен в правильный массив, я использую динамическое приведение Item* item
к (например) Equipment* equi
так что я могу добавить его в массив оборудования. Я хочу сделать это одним и тем же методом, потому что он более интуитивно понятен, в противном случае разные методы будут иметь похожий код
addToInventory(Item* item)
{
if (item->type == 'e')
{
Equipment* newEquip = dynamic_cast<Equipment*>(item);
equipmentArr.add(newEquip);//thous arrays are dynamic- the reason I needed to make the conversion explained later
}
else if (item->type == 'm')
{
Modification* newMod = dynamic_cast<Modification*>(item);
modificationArr.add(newEquip);
}
//and so on...
}
Позже я хотел бы добавить модификацию к элементу оборудования Weapon::addMod(Modification* mod)
, И в этом методе я использую другие методы и переменные, которые находятся ТОЛЬКО в классе оружия.
addMod (Modification* mod)
{//all are found ONLY in class Weapon
mod[modCount] = mod; //an array of Modification* pointers
modCount++;
calcEfficiency();
}
Но когда я хочу сделать простую вещь для печати инвентаря, мне нужно либо скопировать-вставить и отредактировать некоторый код для преобразования указателей в массивах, чтобы я мог передать их тем же способом печати, или скопировать-вставить и редактировать тот же код для печати. Существует третий вариант — сделать массивы для всех массивов указателей на объекты Item. Я попробовал последний вариант.
Избавился от кастинга в addToInventory(Item* item)
, ура! Но это вызвало необходимость использовать приведение КАЖДЫЙ раз, когда мне нужно вызывать такие методы, как Weapon::addMod(Modification* mod)
и в других местах. В противном случае мне нужно будет поместить приведение в метод, но я хочу, чтобы метод явно Equipment*
аргумент.
Проект все еще находится на ранней стадии разработки, поэтому я не знаю, сколько еще мне может понадобиться использования приведения, поэтому я могу при необходимости переключаться между различными типами указателей.
Итак, в аналогичном случае, как я должен переключаться между различными типами указателей?
Вы можете представлять черты (а именно Equipment
а также Modification
) вашего (широкого) Item
реализации как чистые виртуальные классы (то есть интерфейсы). Таким образом, динамическое приведение и проверка динамического приведение для этих интерфейсов в порядке и уменьшит шум для обработки для реальных реализаций Equipment
а также Modification
,
Другой способ заключается в использовании Шаблон CRTP а также static_cast<Interface*>
иметь проверки времени компиляции для ваших интерфейсов.
Зависит от вашего варианта использования, какой способ является более подходящим. Как правило большого пальца: