C++ Добавление объектов дочерних классов в вектор родительского класса

У меня есть следующая иерархия классов: Класс Crocodile наследуется от Oviparous, который наследуется от Animal

Мне нужно хранить объекты типа Crocodile, Goose, Pelican, Bat, Whale и SeaLion внутри вектора, поэтому:

1- Я создаю глобальный вектор:

vector<Animal*> animals;

2- Добавляю в вектор объекты (Крокодил, Гусь, Пеликан, Летучая мышь, Кит, Морской лев):

animals.push_back(new Crocodile(name, code, numberofEggs));

3- я перебираю вектор, чтобы напечатать каждый объект на столе

for (size_t i = 0; i < animals.size(); ++i){
    /* now the problem is here, each animal[i] is of type = "Animal", not Crocodile, or Goose, etc..
   /* so when I try to do something like the line below it doesn't work because it can't find the method because that method is not on the Animal Class of course */
   cout << animals[i]->GetName(); // THIS WORK
   cout << animals[i]->GetNumberofEggs(); //THIS DOESN'T WORK
   /* when I debug using the line below, every object on the vector is returning "P6Animal" */
   cout << typeid(animals[i]).name(); // P6Animal instead of Crocodile
}

Я думаю, что это связано с этим сообщением std::vector для родительского и дочернего классов и я думаю, что проблема заключается в нарезке объектов, поэтому я попытался создать вектор следующим образом:

vector<unique_ptr<Animal>> animals;
//and adding the objects like this
animals.push_back(unique_ptr<Animal>(new Crocodile(name, code, numberofEggs)));

Но ничего ????

Любая помощь будет здорово! Благодарю вас!


person Pedro    schedule 25.06.2020    source источник
comment
Поскольку вы используете указатели, это не проблема нарезки. Однако использование интеллектуального указателя лучше, чем необработанный указатель, поэтому продолжайте использовать его. Я подозреваю, что происходит то, что у вас нет функции GetNumberofEggs() в вашем базовом классе. Пожалуйста, работайте над минимально воспроизводимым примером .   -  person Retired Ninja    schedule 25.06.2020
comment
typeid::name не так полезен, как хотелось бы. Тип действительно является указателем на Animal. Рассмотрите возможность добавления виртуальной функции name к animal.   -  person user4581301    schedule 25.06.2020
comment
Вот небольшой пример, который может помочь объяснить проблему typeid: ideone.com/UWwdXF.   -  person Retired Ninja    schedule 25.06.2020
comment
Я с Ниндзя. Но как далеко вы готовы зайти ради этих яиц? У животных есть яйца, но многие из них не откладывают яйца, поэтому в зависимости от того, что вы подразумеваете под GetNumberofEggs, это может не иметь смысла в Animal.   -  person user4581301    schedule 25.06.2020


Ответы (2)


Ваша проблема в том, что вы пытаетесь получить доступ к определенному дочернему методу, который не определен в родительском классе, из объекта, который имеет родительский тип.

Вы должны хранить объект как тип, с которым вы хотите работать, поэтому, если вы сохраняете массив Animal, подразумевается, что вы будете работать с объектами, используя только интерфейс Animal, независимо от исходного типа объекта. В противном случае, если вам нужно получить доступ к методам из класса Opivarous, вы должны подумать о том, чтобы хранить свои объекты как Opivarous (или Crocodile и т. д.).

Также вы можете использовать dynamic_cast для этой цели:

if(Crocodile* crocodile = dynamic_cast<Crocodile*>(animals[i]))
{
    cout << crocodile->GetNumberofEggs();
}

Это самый простой способ решить проблему, но он показывает, что в вашем коде есть проблемы с архитектурой.

person LastSymbol0    schedule 25.06.2020

Я заставил его работать с виртуальным методом Print в классе Animal, а затем переопределить этот метод из дочерних классов. Всем спасибо!

person Pedro    schedule 26.06.2020