Если пример действительно является репрезентативным, виртуальная функция решит вашу непосредственную проблему гораздо более аккуратно.
В любом случае, самый простой ответ, если у ваших классов есть виртуальные функции, это использовать dynamic_cast
, чтобы проверить, принадлежит ли объект заданному типу. Например:
for (int i=0; i<v.size(); i++) {
if (Lion *lion = dynamic_cast<Lion *>(v[i]))
lion->chowMeat();
else if(Butterfly *butterfly = dynamic_cast<Butterfly *>(v[i]))
butterfly->drinkNectar();
}
Он встроен в язык и предназначен только для проверки, действительно ли указатель на базу указывает на объект более производного типа.
Другой вариант - иметь в своем базовом классе какую-то виртуальную функцию GetType, которую вы переопределяете для каждого класса, чтобы вернуть что-то (целое число, объект, что угодно), которое однозначно идентифицирует этот класс. Затем вы вызываете эту функцию во время выполнения и изучаете результат, чтобы выяснить, на какой объект указывает указатель.
dynamic_cast
имеет то преимущество, что он встроен в язык и не требует никаких усилий с вашей стороны для поддержки. Использование собственной функции имеет более предсказуемые характеристики производительности в широком диапазоне компиляторов и позволяет хранить данные, отличные от того, какой тип объекта на самом деле - но вы все равно должны написать все сами.