#include <iostream>
using std::cout;
using std::endl;
using std::ostream;

#include <vector>
using std::vector;

#include <set>
using std::set;

#include <string>
using std::string;

#include <algorithm>
using std::set_intersection;

#include <iterator>
using std::back_inserter;

class Luokkatyyppi {
        set<string> tyyppi;
public:
        Luokkatyyppi(const string& nimi) {
                tyyppi.insert(nimi);
        }

        void lisaa(const string& nimi) {
                tyyppi.insert(nimi);
        }

        bool on_tyyppia(const Luokkatyyppi &toinen) {
                if (this==&toinen) return true;

                vector<string> out;

                set_intersection(
                    tyyppi.begin(), tyyppi.end(),
                    toinen.tyyppi.begin(), toinen.tyyppi.end(),
                    back_inserter(out));

                return !out.empty();
        }
        friend
        ostream& operator << (ostream& out, const Luokkatyyppi &l);
};

ostream& operator << (ostream& out, const Luokkatyyppi &l) {
        for (set<string>::const_iterator i=l.tyyppi.begin();
             i!=l.tyyppi.end();
             ++i)
                out << *i << ' ';
        return out;
}


class Yliluokka {
        Luokkatyyppi tyyppi;
public:
        static const string TYYPPINIMI;

        Yliluokka() : tyyppi(TYYPPINIMI) {
        }
        void lisaa(const string &nimi) {
                tyyppi.lisaa(nimi);
        }
        bool on_tyyppia(const string& nimi) {
                return tyyppi.on_tyyppia(nimi);
        }
        void tulosta_tyypit() {
                cout << "Tyypit: " << tyyppi << endl;
        }
        void tee(int k) {
                cout << "Teenpä jotain " << k << endl;
        }
};

const string Yliluokka::TYYPPINIMI="Yliluokka";

class Aliluokka {
        Luokkatyyppi tyyppi;
        Yliluokka yli;
public:
        static const string TYYPPINIMI;
        Aliluokka() : tyyppi(TYYPPINIMI) {
                tyyppi.lisaa(Yliluokka::TYYPPINIMI);
        }
        bool on_tyyppia(const string& nimi) {
                return tyyppi.on_tyyppia(nimi);
        }
        void tulosta_tyypit() {
                cout << "Tyypit: " << tyyppi << endl;
        }
        void tee(int k) {
                yli.tee(k);
                cout << "Teinpä muutakin" << endl;
        }
};

const string Aliluokka::TYYPPINIMI="Aliluokka";

int main(void) {

        Yliluokka a;
        Aliluokka b;

        b.tulosta_tyypit();

        cout << b.on_tyyppia(Yliluokka::TYYPPINIMI) << endl;

        cout << "testataan b.tee(23):" << endl;
        b.tee(23);

        return 0;
}