Мне нужно сделать вектор, содержащий объекты базового класса и производного класса и знать, какой элемент какой

Я работаю над игрой, в которой есть монстры и драконы. Драконы могут делать все, что могут делать монстры, кроме того, что они могут дышать огнем.

Я создал класс типа «монстр» и класс, который наследуется от монстра под названием «дракон».

Затем у меня есть класс под названием «монстры», который имеет в качестве частного члена вектор, который будет содержать элементы дракона и монстра.

В основном игровом цикле мне нужно циклически перемещаться по вектору и пускать огонь, если текущий элемент — дракон, и ничего не делать, если он просто монстр.

Я пытался использовать typeid (), но он всегда возвращает monster *, является ли текущий элемент простым монстром или драконом.

Есть ли способ сделать это или нет смысла даже использовать наследование в этом случае?
Будет ли для драконов больше смысла не наследовать, а вместо этого оставаться независимым от монстра?

Любой совет приветствуется.

-1

Решение

Вы мог сделать что-то подобное

class Monster {};
class Dragon : public Monster
{
public:
void BlowFire() {}
}

std::vector<Monster*> monsters; // Collection of monsters

for(auto it = monsters.begin(); it != monsters.end(); ++it)
{
Dragon* pDragon = dynamic_cast<Dragon*>(*it); // Attempt to convert pointer
if(pDragon)
{
pDragon->BlowFire(); // If it is indeed a Dragon, blow fire.
}
}

Но звучит так, будто вы должны организовать свои занятия немного лучше. Почему бы вам не иметь все свои классы монстров Attack метод? Таким образом, вы можете переопределение методы для каждого типа монстров.

class Monster
{
public:
virtual void Attack() {} // All monsters can attack
};

class Dragon : public Monster
{
public:
virtual void Attack() { // Do something special for a Dragon. }
};

Monster myMonster;
Dragon myDragon;
myMonster.Attack(); // Generic monster attack.
myDragon.Attack(); // Special super dragon fire attack!
3

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

Есть два возможных подхода: использовать виртуальную функцию или использовать dynamic_cast, Если monster имеет виртуальную функцию blow_fire() это ничего не делает, dragon может переопределить это, чтобы сделать все, что подходит для дракона. Тогда вы просто позвоните для всех monster объекты, и драконы будут дуть огонь. С помощью dynamic_castкод будет что-то вроде этого:

if (dragon *dragon_ptr = dynamic_cast<dragon*>(monster_ptr)) {
dragon_ptr->blow_fire();
}

Обычно это считается плохим подходом, потому что он не растет естественным образом. Если вы добавили монстра другого типа, который может взорвать огонь, вам придется добавить еще одного dynamic_cast, С виртуальной функцией новый тип просто переопределит виртуальную функцию.

1

Не то, чтобы это был лучший способ сделать это, но просто для вашей информации, вы звонили typeid на указатель который не работает, если вы хотите тип времени выполнения объекта. typeid делает работать во время выполнения, когда это необходимо, но вам нужно разыменовать указатели на полиморфные типы:

typeid(*monsterpointer)

И это получит тип во время выполнения *monsterpointerбудь то monster или же dragon,

Тем не мение, typeid только для точных сравнений, поэтому, если вы добавите еще один класс с именем ImpairedDragon что наследует от Dragon, typeid код сломается и не будет работать с ними. Так что вы, вероятно, должны использовать dynamic_cast которая работает с наследованием или, что еще лучше, с виртуальной функцией, если вы можете придумать, как правильно ее использовать.

1

Если в вашем контейнере есть указатели на монстров, то общедоступные члены-монстры — это все, что вы можете получить с помощью этих указателей безопасным для типов способом (из моей памяти). Вы можете попробовать прибегнуть к дизайну на основе интерфейса, например, COM, чтобы можно было запросить у базового класса монстров какие-либо дополнительные функции, например интерфейсы. Я бы предоставил вам образец, но мой обеденный перерыв закончился.

1

Как насчет размещения пустого (без операции) виртуального blowFire в базовом классе, а затем переопределить его с чем-то в производном классе?

Было бы еще лучше переименовать метод в specialAttack или похожее родовое имя, поэтому вам не нужно добавлять похожие методы для других видов монстров.

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