Lesson 178 +55 XP

Project 9: Animal Sounds (inheritance + virtual)

Project 9: Animal Sounds (inheritance + virtual)

You learned about inheritance and virtual functions; now watch them work. A base Animal declares speak() as virtual, each derived animal overrides it, and a loop of pointers prints the right sound for each one.

The goal

Create an Animal base with a virtual speak(), derive Dog and Cat with overrides, store them in a vector<Animal*>, and play every sound polymorphically.

What you practice

  • A base class with virtual methods
  • Derived classes that override behavior
  • A polymorphic collection of pointers
  • A range-for loop that calls speak() through the base type

Starter code

This compiles and runs as-is:

#include <iostream>
#include <vector>
using namespace std;

class Animal {
public:
  virtual void speak() const {
    cout << "..." << endl;
  }
  virtual ~Animal() {}
};

class Dog : public Animal {
public:
  void speak() const override {
    cout << "Woof!" << endl;
  }
};

class Cat : public Animal {
public:
  void speak() const override {
    cout << "Meow!" << endl;
  }
};

int main() {
  vector<Animal*> zoo;
  zoo.push_back(new Dog());
  zoo.push_back(new Cat());

  for (Animal* a : zoo) {
    a->speak();
  }

  for (Animal* a : zoo) delete a;
  return 0;
}

Step-by-step

  1. Run the starter and confirm Woof! and Meow! both print.
  2. Add a Pig class with cout << "Oink!" << endl;.
  3. zoo.push_back(new Pig()); - no other change needed.
  4. Now delete the virtual keyword from Animal::speak and recompile. Watch how the sounds change - that is what virtual is for.
  5. Put the virtual keyword back.
  6. Run the final program and confirm all three animals speak their own sound.

Checklist

  • [ ] Animal::speak is declared virtual
  • [ ] Dog and Cat override it with override
  • [ ] The animals are stored as Animal* pointers
  • [ ] The loop calls speak() on the base type
  • [ ] Each animal prints its own sound
  • [ ] The program compiles and runs

TL;DR

  • virtual lets a derived class replace a base method.
  • override tells the compiler you meant to replace it.
  • A vector<Animal*> can hold every derived animal.
  • A single loop over the base type plays the right sound.