#include <iostream>
#include <string>
#include <typeinfo>

class Pet {
  string name;
public:
  Pet(const string & aName) : name(aName) {}
  virtual void talk() = 0;
  // add virtual later
  virtual string print() const { return name; } 
};

class Dog : virtual public Pet {
public:
  Dog(const string & aName) : Pet(aName) {}
  void talk() { cout << "Woof woof" << endl; }
}; 

class Cat : virtual public Pet {
public:
  Cat(const string & aName) : Pet(aName) {}
  void talk() { cout << "Meow meow" << endl; }
  void climb() { cout << "Climbing..." << endl; }
};

ostream & operator<<(ostream & os, const Pet & pet) {
  return (os << pet.print());
}

// write in class
class Chihuahua : public Dog, public Cat {
public:
  Chihuahua(const string & aName) : Dog(aName), Cat(aName), Pet(aName) {}
  void talk() { Dog::talk(); }
};

int main() {
  Chihuahua taco("Taco");
  taco.talk();
  taco.Dog::talk();

  taco.Cat::talk();

  // explain?
  dynamic_cast<Cat &>(taco).talk();

  Pet & garf = *(new Cat("Garfield"));
  try {
    Dog & d = dynamic_cast<Dog &>(garf);
    d.talk();
  }
  catch (bad_cast) {
    cerr << "Not a dog!" << endl;
  }
}

