#include <iostream>
#include <typeinfo>
#include <deque>

/*
This is a brief look at RTTI.

Geneally RTTI is a basic mechanism.  

The exception handing in C++ is also basic.
 
I was looking at RTTI and smart pointers, but
 I should investigate Boost. I don't know how paradims
 interact with exception handing - maybe new possibilities,
 mabe exception handing is still the bleeding edge I just
 don't know.

Having said this it should be noted that it is easy (somewhat)
 to write your own smart pointers without complicated
 C++ machinery. Especially since templates have matured.
*/

using namespace std;

// Display the variable and value.
#define SHOW(x) #x << '=' << (x)

class a0
{
public:

  virtual void fly() { cout << "void a0::fly()" << endl; }
};

class a1 : public a0
{
public:
                                                                                
  virtual void fly() { cout << "void a1::fly()" << endl; }
};

class a2 : public a0
{
public:
                                                                                
  virtual void fly() { cout << "void a2::fly()" << endl; }
};


void test01()
{
  cout << "Investigating RTTI" << endl;

  a0* x0 = new a1();

                                          /* String     */
  cout << typeid( x0 ).name() << endl;    /* P2a0       */
  cout << typeid( *x0 ).name() << endl;   /* 2a1        */

  x0 = new a2();
  cout << typeid( *x0 ).name() << endl;   /* 2a2        */
}

/* Serious problem, the following code segfaults when accessing
   a dead pointer.

   Im using gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)

   Whats the point of try/catch if it can't handle this?
*/

/* test02() incorrectly tries to ask if a pointer is alive
    or dead using RTTI.
    I believe that RTTI was not designed to support such a request.
*/
void test02()
{
  a0* x0 = new a1();

  /* Intentionally have a reference to a dead pointer. */
  delete x0;

  cout << "ok" << endl;

  try
  {
    typeid(*x0); /* An exception should be thrown. */
    cout << typeid(*x0).name() << endl;

  } catch( ... )
  {
    cout << "Invalid reference caught." << endl;
  }
}

void test03()
{
  cout << "Investigating RTTI" << endl;
                                                                                
  a0* x0 = new a1();
  a0* x1 = new a2();
  a0* x2 = new a2();
  a0* x3 = new a1();
  a0* x4 = new a0();
                                                                                
                                          /* String     */
  cout << SHOW( typeid( x0 ).name() ) << endl;    /* P2a0       */
  cout << SHOW( typeid( *x0 ).name() ) << endl;   /* 2a1        */
  cout << SHOW( typeid( x1 ).name() ) << endl;    /* P2a0       */
  cout << SHOW( typeid( *x1 ).name() ) << endl;   /* 2a1        */
  cout << SHOW( typeid( x2 ).name() ) << endl;    /* P2a0       */
  cout << SHOW( typeid( *x2 ).name() ) << endl;   /* 2a2        */
  cout << SHOW( typeid( x3 ).name() ) << endl;    /* P2a0       */
  cout << SHOW( typeid( *x3 ).name() ) << endl;   /* 2a1        */
  cout << SHOW( typeid( x4 ).name() ) << endl;    /* P2a0       */
  cout << SHOW( typeid( *x4 ).name() ) << endl;   /* 2a0        */

  cout << endl << endl << endl;
  cout << SHOW(typeid( *x1)==typeid(*x0)) << endl;
  cout << SHOW(typeid( *x2)==typeid(*x0)) << endl;
  cout << SHOW(typeid( *x3)==typeid(*x0)) << endl;
  cout << SHOW(typeid( *x4)==typeid(*x0)) << endl;
  cout << SHOW(typeid( *x2)==typeid(*x1)) << endl;
  cout << SHOW(typeid( *x3)==typeid(*x1)) << endl;
  cout << SHOW(typeid( *x4)==typeid(*x1)) << endl;
  cout << SHOW(typeid( *x3)==typeid(*x2)) << endl;
  cout << SHOW(typeid( *x4)==typeid(*x2)) << endl;
  cout << SHOW(typeid( *x4)==typeid(*x3)) << endl;
  cout << SHOW(typeid( *x4)==typeid(*x4)) << endl;

}


int main()
{
  test03();

  return 0;
}

