Reminder: Implementing a Class
Implementing the Cow
and Barn
Classes
Here's the implementation of our Barn
class:
Barn::Barn() : cowCapacity_{1}, residentCow_{"Bessie", 42} {
// Nothing (else) to do here!
}
Barn::Barn(size_t numCows) : cowCapacity_{numCows}, residentCow_{"Bessie", 42} {
if (cowCapacity_ != 1) {
throw std::invalid_argument("Barns can only hold one cow!");
}
}
void Barn::feed() {
residentCow_.feed();
}
You can explore this code by running it online (although you totally can, you don't need to look at the implementation of the Cow
class).
In Java I just wrote all the code for my classes in one file. Why is it that we have to divide things into header files and implementation files?
It is how C did things in 1972.
Pfft!
Meh.
But there is some sense in having a publicly viewable header file separate from the implementation file.
But we put some
private
details in our header file.The header file isn't just for humans to read, it's for the compiler, too. Those details are things it needs to know.
Can you go over the stuff with the
:
? I still don't know why we need that.The member-initialization list? We will!
Checking In…
Review the code for the Barn
class (and, ideally, run it in Online GDB using the link above).
Remember, C++ promises that when we hit the opening curly brace of the constrictor body, all the data members will have been initialized. It will either follow what we said in the class declaration itself (which, in our case, default-initialized all the data members), or we can override that behavior for specific data members using a member-initialization list.
In CS 70 (and in C++ code generally), it is considered bad style to perform assignment to data members in the body of a constructor when that initialization could have been done in a member-initialization list. It's wasteful to set an initial default value we don't actually want, and then immediately overwrite it with the actual value we do want.
In our code for the Barn
class, since we are initializing all of the data members of the Barn
instance in the member-initialization list, everything is set up and ready to go by the time we get to the body of the constructor, so there's no more set-up work to do.
So why have a body to the constructors at all?
Good question! There are times when we can't do all the set up we want in the member-initialization list. Plus, sometimes you want to check things to make sure everything is okay, or produce debugging output.
You can see those last two examples in our classes here, and we'll see the “more set-up” case soon.
(When logged in, completion status appears here.)