#include <iostream>
#include <string>

using namespace std;

class Pet
{
protected:
    string type;
    string name;
public:
    Pet(const string& arg1, const string& arg2);
    virtual void whoAmI() const;
    virtual string speak() const = 0;
};

Pet::Pet(const string& arg1, const string& arg2): type(arg1), name(arg2)


{}
void Pet::whoAmI() const
{
    cout << "I am an excellent " << type << " and you may refer to me as " << name << endl;
}

class Dog : public Pet
{
public:
    using Pet::Pet;
    void whoAmI() const override { std::cout << "Dog::whoAmI\n";}  // override the describe() function
    string speak() const override;

};

string Dog::speak() const
{
    return "Arf!";
}

class Cat : public Pet
{
public:
    using Pet::Pet;

    string speak() const override;
    // Do not override the whoAmI() function
};

string Cat::speak() const
{
    return "Meow!";
}

ostream& operator<<(ostream& out, const Pet& p)
{
    p.whoAmI();
    out << "I say " << p.speak();
    return out;
}

int main()
{
    Dog spot("dog","Spot");
    Cat socks("cat","Socks");
    Pet* ptr = &spot;
    cout << *ptr << endl;
    ptr = &socks;
    cout << *ptr << endl;
}
