Различать производные объекты в векторе базовых указателей в С++

В ответ на этот вопрос Vector/Container, состоящий из различных производных объектов в C++ Я попытался улучшить свой код. Теперь я храню указатели на свои производные объекты в одном векторе, но я не уверен, как затем получить доступ к их функциям-членам производного класса и разбить один вектор на подвекторы каждого соответствующего производного типа.

#include <vector>
#include <memory> // for unique_ptr
#include <iostream>

using namespace std;

class Fruit {};
class Banana: public Fruit { void cout_banana() { cout << "i am a banana" << endl; } };
class Apple : public Fruit { void cout_apple() { cout << "i am an apple" << endl; } };

class FruitBox
{
    vector<unique_ptr<Banana>> vec_banana;
    vector<unique_ptr<Apple>>  vec_apple;

public:
    FruitBox(const vector<unique_ptr<Fruit>> &fruits)
    {
        for (const unique_ptr<Fruit> &f : fruits)
        {
            // How to figure out if f is Banana or Apple and then
            // 1) Print either cout_banana or cout_apple
            // 2) Store/Move f in either vec_banana or vec_apple
        }
    }
};

void main()
{
    vector<unique_ptr<Fruit>> inputs;
    inputs.emplace_back(new Banana());
    inputs.emplace_back(new Apple());

    FruitBox fbox = FruitBox(inputs);
}

person Phil-ZXX    schedule 22.05.2018    source источник
comment
см. RTTI - stackoverflow .com/questions/351845/   -  person Joseph D.    schedule 22.05.2018
comment
почему вы хотите различать производные классы? Чего вы хотите добиться в итоге? Обычно у вас есть несколько производных функций, специфичных для класса, из-за специфичных для класса реализаций. Но может быть, вы хотите что-то другое. Таким образом, ответ зависит от того, что вы хотите в конце концов.   -  person JHBonarius    schedule 22.05.2018


Ответы (1)


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

принцип подстановки Лисков гласит, что "если S является подтипом T, то объекты типа T можно заменить объектами типа S (т. е. объект типа T можно заменить любым объектом подтипа S)." Здесь это не так.

Вместо того, чтобы определять cout_xyz в своих подклассах, вы должны написать void cout_fruit() как абстрактный метод в class Fruit и переопределить его в подклассах.

class Fruit { public: virtual void cout_fruit() = 0; };
class Banana: public Fruit { public: void cout_fruit() override { cout << "i am a banana" << endl; } };
class Apple : public Fruit { public: void cout_fruit() override { cout << "i am an apple" << endl; } };
// [...]

Затем для каждого фрукта вы можете просто вызвать f->cout_fruit().

person andreee    schedule 22.05.2018
comment
А для бонусных баллов вы бы изменили его на virtual std::basic_ostream& output_fruit(std::basic_ostream&) и реализовали operator<<, который вызывает его. - person Caleth; 22.05.2018