Skip to content

In-Class Exercise

6. Practice

Aliens have discovered that eating fish is good for their skin. As a result, in addition to cows, they now specifically want to abduct carps as well. A complete overhaul of the abduction modules is necessary: help create the new kind of representation that will allow spaceships to abduct any animal in the future!

motto


Task Zero!

Before starting the exercises, download the starter code. We will be working by extending this!

Starter Code

starter.cpp


  1. Refactor the starter code! The Cow and Sheepdog classes can be considered similar. Both represent animals, both have a private name data member, and we want to include a makeSound() function in both classes. This function has the same signature but different internal behavior.

    • What is the conventional object-oriented approach to handling such similarities?
  2. Create the Animal base class and make the necessary modifications so that both Cow and Sheepdog 2are subclasses of it!

    • Move the name data member into the base class! Create a getter, setter, and a constructor with a string parameter to initialize it.
    • Is it necessary to delete the name data member from the child classes? Why?
    • For now, remove the name member from the child classes!
    • Try compiling the code!
    • Use protected visibility!
    • Handle the child class constructors!
      • In Sheepdog, provide a default constructor that sets the name to "Bodri".
      • In Cow, keep the existing parameterized constructor but properly initialize the base class member.
  3. Add a makeSound constant method to the Animal base class. This function should return the string: "Makes a sound:".

    • Override this behavior in the subclasses!
    • For Cow: "Makes a sound:moo"
    • For Sheepdog: "Makes a sound:woof"
    • How can the code be simplified to avoid always repeating the "Makes a sound:" prefix?
  4. Extend the Spaceship class! Add a public method inspect(Animal a) that takes the animal to be abducted as a parameter. Return true if the animal can be abducted (i.e., if it’s a cow), and false otherwise (everything else).

    • The check should be based on the string returned by makeSound.
    • If the returned string ends with "moo", abduction is allowed.
    • If the returned string is shorter than 3 characters (shorter than "moo"), throw a std::runtime_error("too short").
    • In main, call the inspect method on both a cow and a sheepdog. What do you observe?
    • Print the return value of makeSound() inside the inspect() function!
  5. Extend the Spaceship class with another method inspectRef(const Animal& a) which takes a constant reference to an animal! Its implementation should be identical to that of inspect(). Try using it!

  6. Make the makeSound function virtual in the base class! Run both the inspect() and inspectRef() methods!
  7. Try removing the const from the Sheepdog’s makeSound() method! Run the inspectRef method like this too. What do you observe?
    • Apply the override specifier to the makeSound overrides!
  8. Write a custom exception class named AncientAnimalException, publicly inheriting from std::exception!
  9. Override the what() method from std::exception: const char* what() const noexcept The returned message should be: "Error: ancient animal inspection!"
  10. Throw an AncientAnimalException in inspectRef if the object passed as parameter returns the base class string ("Makes a sound:") from makeSound()!
  11. Test the inspectRef function by passing a base Animal object!
    • Catch the exception in main using a try-catch block:
    • Catch by value and print the value returned by the what() method to cout.
    • Catch by value, but using the base type (std::exception). Print the value returned by what().
    • Modify the type to const std::exception& (constant reference) and test this as well!
  12. Write a Carp class inheriting from Animal, where the makeSound function returns an empty string, since fish don’t speak (at least, we can't hear them). Every carp should be named "Nemo", since we wouldn’t be able to tell them apart anyway. Test the inspectRef function with this as well!
    • How can you handle std::runtime_error separately from other exception types in a try-catch block?
  13. How can you prevent the general Animal class from being instantiated? Implement it!
  14. What happens if you try to store Animal types in a vector but add a Cow to it?
  15. How can you prevent overriding the getName method in the Animal class?

Got stuck or couldn’t follow the class? Or just want to review?
Here’s one possible solution to the exercises!

In-class solution

solution.cpp



Last update: 2025-11-27
Created: 2025-11-27