#include <iostream>
#include <list>
#include <string>
#include <memory>
using namespace std;

class Animal {
public:
    virtual void speak() = 0;
    virtual ~Animal() {}; // Always a good thing if the class has virtual members
    string name;
};

class Dog : public Animal {
public:
    Dog(string n) { this->name = n; }
    void speak() { cout << this->name << " says WOOF!" << endl; }    
};

class AnimalQueue {
    std::list<Animal*> animals;
public:
    void enqueue(Animal* a) {
        animals.push_back(a); // Copy the pointer
    }
    Animal* dequeue() {
        Animal *d = animals.front();
        animals.pop_front(); // Destroy the pointer
        return d;
    }
};

int main() {
    AnimalQueue q;
    std::unique_ptr<Dog> d = std::make_unique<Dog>("Rex");
    q.enqueue(d.get()); // This will now store the pointer to the object

    // Try with dog-specific command
    Animal *sameDog = q.dequeue(); // d.get() and sameDog are now pointing at the same object
    if (d.get() == sameDog)
    	std::cout << "d.get() == sameDog" << std::endl;
    std::cout << sameDog->name << std::endl;// Prints "Rex"
    sameDog->speak();

    return 0;
}