//: C10:InnerClassIdiom.cpp
// Z knihy "Myslíme v jazyce C++, část 2" od Bruce Eckela a Chucka Allisona.
// (c) 1995-2004 MindView, Inc. Všechna práva vyhrazena.
// Přečtěte si podmínky používání zdrojových kódů umístěné v souboru 
// 'Licence.txt' dodávaném spolu s balíčkem kódu dostupným na www.MindView.net.
// Příklad idiomu "vnitřní třída".
#include <iostream>
#include <string>
using namespace std;

class Pingnutelna {
public:
  virtual void ping() = 0;
};

void volatPing(Pingnutelna& p) {
  p.ping();
}

class Bingnutelna {
public:
  virtual void bing() = 0;
};

void volatBing(Bingnutelna& b) {
  b.bing();
}

class Vnejsi {
  string nazev;
  // Definovat jednu vnitřní třídu:
  class Vnitrni1;
  friend class Vnejsi::Vnitrni1;
  class Vnitrni1 : public Pingnutelna {
    Vnejsi* rodic;
  public:
    Vnitrni1(Vnejsi* p) : rodic(p) {}
    void ping() {
      cout << "ping voláno pro "
        << rodic->nazev << endl;
      // Přistup k datům objektu vnější třídy
    }
  } vnitrni1;
  // Definovat druhou vnitřní třídu:
  class Vnitrni2;
  friend class Vnejsi::Vnitrni2;
  class Vnitrni2 : public Bingnutelna {
    Vnejsi* rodic;
  public:
    Vnitrni2(Vnejsi* p) : rodic(p) {}
    void bing() {
      cout << "bing voláno pro "
        << rodic->nazev << endl;
    }
  } vnitrni2;
public:
  Vnejsi(const string& nm)
  : nazev(nm), vnitrni1(this), vnitrni2(this) {}
  // Vrátit referenci na rozhraní 
	//implementované vnitřními třídami.
  operator Pingnutelna&() { return vnitrni1; }
  operator Bingnutelna&() { return vnitrni2; }
};

int main() {
  Vnejsi x("Ping Pong");
  // Jako přetypování nahoru na více bázových typů!:
  volatPing(x);
  volatBing(x);
} ///:~
