CS 70

Example: Using Our Petting Zoo

Revisiting Our engaegWith() Function

  • LHS Cow speaking

    Now we can update our engageWith() function to take a reference to an Animal:

void engageWith(Animal animal) {
    animal.speak();
    animal.feed();
}

int main() {
    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);

    return 0;
}
  • Dog speaking

    This is great. It's totally going to print

    ## Petting the Cow:
    Bessie says: Mooooo
    Bessie eats
    
    ## Petting the Raptor:
    Peri says: Rawrrr
    Peri eats
    

Is Dog correct here?

Run the code yourself and see what happens:

What happened when you ran the code?

First, copy and paste the output.

Any ideas about why that was the output?

The output looks like

# Petting the Cow:
Bessie makes nonspecific animal noises
Bessie eats

# Petting the Raptor:
Peri makes nonspecific animal noises
Peri eats
  • Horse speaking

    Hay! Why didn't the Cow moo? Why didn't the Raptor rawr?

  • Cat speaking

    I think I see something!

  • LHS Cow speaking

    Oh?

  • Cat speaking

    engageWith() is taking its argument as a copy, right?

  • LHS Cow speaking

    It is.

  • Cat speaking

    So when the copy is made, the compiler is only copying the Animal parts to make a new Animal object that doesn't have the happiness_ or anger_ data members, so it literally isn't a Cow or Raptor, it's just an Animal.

  • LHS Cow speaking

    That's right! Because engageWith() takes an Animal by value, it only copies the common Animal parts of our Cow or Raptor objects to make the Animal copy.

  • RHS Cow speaking

    FWIW, this process is sometimes called “slicing”, as we've sliced away the Cow- or Raptor-specific parts to be left with a plain generic Animal.

  • Dog speaking

    I bet if we change it to take a reference, things will be better.

  • LHS Cow speaking

    Let's try that!

Either edit the code to add the ampersand, or run this updated version.

Are things better?

  • Vader speaking

    Noooooooooo!

  • Dog speaking

    How did that not fix it??

  • LHS Cow speaking

    Hang tight. We can totally figure out a way to make this petting zoo of Cows and Raptors work.

  • Goldblum speaking

    Again I ask, can or should?

Things are, in fact, working exactly as Duck said they should on the Before You Start page.

Specifically, Duck said that when figuring out what function to call, we should use the type of the variable.

In this case, our code looks like

void engageWith(Animal& animal) {
    animal.speak();
    animal.feed();
}

The type of animal is Animal, so, as promised, we call Animal::speak.

  • Bjarne speaking

    So C++ is doing exactly what you wanted.

  • Duck speaking

    Uh…

  • LHS Cow speaking

    Watch what you wish for.

  • RHS Cow speaking

    It turns out that we don't want to decide what function to call based on the (static) type at compile time (Animal)—we really want to decide based on the actual object we have at runtime (Cow or Raptor).

  • Bjarne speaking

    C++ can do that, too. If you ask for it.

  • Pig speaking

    Tell me MORE!

(When logged in, completion status appears here.)