
// ConsoleApplication1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <memory>

using namespace std;

struct Base
{
    int i;

    virtual void print() = 0;
};

struct Derived:Base
{
    int j;
    virtual void print()
    {
        cout << i << " " << j << endl;
    }
};

struct Special:Base
{
    virtual void print() {
        cout << "special print" << endl;
    }
};

class Animal
{
public:
    virtual void sound() = 0;

private:

};

class Fox : public Animal
{
public:
    virtual void sound() {
        cout << "I am a fox" << endl;
    }
};

class Penguin : public Animal
{
public:
    virtual void sound() {
        cout << "I am a penguin!" << endl;
    }
};

class House : public Animal
{
public:
    vector<unique_ptr<Animal>> h;

    virtual void sound()
    {
        cout << "house is kicked" << endl;
        for (auto &a : h)
        {
            a->sound();
        }
        cout << "house did its job" << endl;
    }

    void add_animal(unique_ptr<Animal>&& a)
    {
        h.push_back(std::move(a));
    }
};

int main()
{
    /*
    Derived a;
    a.print();
    Base * p = &a;
    p->print();

    std::vector<unique_ptr<Base>> v;
    v.push_back(unique_ptr<Base>(new Derived()));
    v.push_back(unique_ptr<Base>(new Special()));

    for (auto& pp : v)
    {
        pp->print();
    }
    */

    std::vector<unique_ptr<Animal>> zoo;
    zoo.push_back(unique_ptr<Animal>(new Fox()));
    zoo.push_back(unique_ptr<Animal>(new House()));
    zoo.push_back(unique_ptr<Animal>(new Penguin()));

    dynamic_cast<House*>(
        zoo[1].get()
    )->add_animal(unique_ptr<Animal>(new Fox()));

    /* NOTICE
     * Apparently the complicated creation of unique_ptrs is only needed in
     * Visual Studio, gcc can perfectly handle the following code:
     *
    std::vector<unique_ptr<Animal>> zoo;
    zoo.push_back(make_unique<Fox>());
    zoo.push_back(make_unique<House>());
    zoo.push_back(make_unique<Penguin>());

    dynamic_cast<House*>(
        zoo[1].get()
    )->add_animal(make_unique<Fox>());
     *
     * It would be interesting to see the reason though.
     */

    for (auto&& a : zoo)
    {
        a->sound();
    }


    return 0;
}

