0

Following up on this question Vector/Container comprised of different derived objects in C++ I have tried to improve upon my code. Now I am storing pointers to my derived objects in single vector, but I am unsure how to then access their derived-class specific member functions and split the single vector into sub-vectors of each respective derived type.

#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);
}
Phil-ZXX
  • 2,359
  • 2
  • 28
  • 40
  • 1
    see RTTI - https://stackoverflow.com/questions/351845/finding-the-type-of-an-object-in-c – Joseph D. May 22 '18 at 08:38
  • 1
    *why* do you want to differentiate between the derived classes? What do you want to achieve in the end? Usually you have several derived class-specific functions due to class-specific implementations. But it could be that you want something else. So the answer is specific on what you want in the end. – JHBonarius May 22 '18 at 08:43

1 Answers1

3

I think your problem is not the implementation per se (checking the actual class would be possible using dynamic_cast, but I won't dive into this here, since it's unnecessary), but rather your understanding of object orientation in the first place - at least in this particular example.

The Liskov Substitution Principle states that "if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e. an object of type T may be substituted with any object of a subtype S)." This is not the case here.

Instead of defining cout_xyz in your subclasses, you should write void cout_fruit() as an abstract method in class Fruit and override it in the subclasses.

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; } };
// [...]

Then, for every fruit, you can simply call f->cout_fruit().

andreee
  • 4,459
  • 22
  • 42
  • 1
    And for bonus points, you would change it to `virtual std::basic_ostream& output_fruit(std::basic_ostream&)` and implement an `operator<<` that calls it – Caleth May 22 '18 at 10:11