/*
* CS 70 Petting Zoo, version 3 (Inheritance with virtual functions)
*
* For simplicity, this file contains all the classes and functions
*/
#include <iostream>
#include <string>
#include <type_traits>
#include <vector>
#include <cstddef>
// Base class
class Animal {
public:
explicit Animal(std::string name, size_t hunger = 0);
virtual ~Animal() = default;
virtual void speak() const = 0;
virtual void feed();
protected:
std::string name_;
size_t hunger_;
};
Animal::Animal(std::string name, size_t hunger) : name_{name}, hunger_{hunger} {
// Nothing (else) to do
}
void Animal::feed() {
std::cout << name_ << " eats" << std::endl;
if (hunger_ > 0) {
--hunger_;
}
}
// An interface class
class Merrymaker {
public:
virtual ~Merrymaker() = default;
virtual void party() const = 0;
};
// Derived class #1: Cow
class Cow : public Animal, public Merrymaker {
public:
explicit Cow(std::string name);
~Cow() override = default;
void speak() const override;
void party() const override;
private:
double happiness_;
};
Cow::Cow(std::string name) : Animal{name, 3}, happiness_{7.5} {
// Nothing (else) to do
}
void Cow::speak() const {
std::cout << name_ << " says: Mooooo" << std::endl;
}
void Cow::party() const {
std::cout << name_ << " parties!!" << std::endl;
}
// Derived class #2: Raptor
class Raptor : public Animal {
public:
explicit Raptor(std::string name);
~Raptor() override = default;
void speak() const override;
private:
double anger_;
};
Raptor::Raptor(std::string name) : Animal{name, 42}, anger_{11} {
// Nothing (else) to do
}
void Raptor::speak() const {
std::cout << name_ << " says: Rawrrr" << std::endl;
}
// A non-Animal class that supports the Merrymaker interface, we'll suppose
// that British prime ministers are party animals
class PrimeMinister : public Merrymaker {
public:
explicit PrimeMinister(std::string name);
void party() const override;
private:
std::string name_;
double charisma_ = 1.0;
};
PrimeMinister::PrimeMinister(std::string name) : name_{name} {
// Nothing (else) to do
}
void PrimeMinister::party() const {
std::cout << name_ << " parties!! (but claims it's all work)"
<< std::endl;
}
void engageWith(Animal& animal) {
animal.speak();
animal.feed();
// The following line will not compile because Animal does not have a
// party() member function, only Cow does.
// animal.party();
// but we can use dynamic_cast to check *at runtime* whether the animal
// is a Cow (or a class derived from Cow), and if so, call party()
Cow* cow = dynamic_cast<Cow*>(&animal);
if (cow != nullptr) {
cow->party();
}
}
void zooTest1() {
std::cout << "# Zoo test 1\n" << std::endl;
Cow bessie("Bessie");
Raptor peri("Peri");
std::cout << "## Petting the Cow:" << std::endl;
engageWith(bessie);
std::cout << "\n## Petting the Raptor:" << std::endl;
engageWith(peri);
}
/* This code won't compile any more, now that Animal is an abstract class */
#if 0 // Prevents the compiler from compiling this code
void zooTest2() {
std::cout << "\n# Zoo test 2\n" << std::endl;
auto cowNames = {"Bessie", "Mabel", "Daisy"};
auto raptorNames = {"Peri", "Rex", "Talon"};
std::vector<Animal> zoo; // This approach turned out to be a bad idea
for (auto name : cowNames) {
Cow tempCow(name);
zoo.push_back(tempCow);
}
for (auto name : raptorNames) {
Raptor tempRaptor(name);
zoo.push_back(tempRaptor);
}
for (auto animal : zoo) {
engageWith(animal);
}
}
#endif
void zooTest3() {
std::cout << "\n# Zoo test 3\n" << std::endl;
auto cowNames = {"Bessie", "Mabel", "Daisy"};
auto raptorNames = {"Peri", "Rex", "Talon"};
std::vector<Animal*> zoo; // This approach actually works
for (auto name : cowNames) {
zoo.push_back(new Cow{name});
}
for (auto name : raptorNames) {
zoo.push_back(new Raptor{name});
}
for (auto animal : zoo) {
engageWith(*animal);
}
while (!zoo.empty()) {
delete zoo.back();
zoo.pop_back();
}
}
void partyTest() {
std::cout << "\n# Party test\n" << std::endl;
std::vector<Merrymaker*> partyGoers;
partyGoers.push_back(new Cow{"Bessie"});
partyGoers.push_back(new PrimeMinister{"Boris Johnson"});
partyGoers.push_back(new PrimeMinister{"Justin Trudeau"});
partyGoers.push_back(new Cow{"Mabel"});
for (Merrymaker* partyGoer : partyGoers) {
partyGoer->party();
}
while (!partyGoers.empty()) {
delete partyGoers.back();
partyGoers.pop_back();
}
}
int main() {
// zooTest1();
// zooTest3();
partyTest();
return 0;
}