Implement Car
Member Functions
In this part of the assignment, you will implement the functionality of the Car
class by filling in the stubs in the car.cpp
file that you created earlier.
We are going to model the need to switch to trains of different sizes, and that can change over the course of a program run, Car
s will need to be dynamically allocated on the heap.
We will represent an empty Car
with capacity 4 using a picture:
[_][_][_][_]~
We will represent a Car
with capacity 4, holding 2 packages, using a picture like
[x][x][_][_]~
Note that bins should always be filled in from left to right.
A full car with capacity 4:
[x][x][x][x]~
Your Tasks
Implement the Car
Default Constructor
Your Car
constructor should
- Initialize the value of
binsInUse_
to be0
. - Iterate over
bins_
and set them all tofalse
, indicating that the car’s bins are all empty.
Implement Functions That Describe Bin Status
After implementing each function, it's a good idea to run
make
(orcs70-make
) to make sure your code compiles correctly and without warnings.
Always Scroll Up to the First Error
Sometimes, especially for code involving <<
, the compiler can give super voluminous errors. Just scroll up to see the first thing that went wrong. Often the errors are long because once the compiler becomes confused, it's unable to correctly interpret the rest of your code. But sometimes just one error can produce tons of output, because the compiler is saying, “I couldn't make sense of your code; here's everything I tried and none of these interpretations worked”. For example, there are numerous versions of operator<<
for different types, and when you give <<
something it can't print, it tells you all the things it can print as part of the error, which ends up being a massive number of things.
Car::getUsage()
- Return the current value of
binsInUse_
.
Car::isFull()
- Return
true
if and only if the number of bins in use is equal to the car capacity. Otherwise it should returnfalse
.
Car::isEmpty()
- Return
true
if and only if the number of bins in use is equal to zero. Otherwise it should returnfalse
.
Functions That Return a bool
As noted in the help page on coding idioms, avoid unnecessary conditional statements that end with code like return true
and return false
.
Implement Functions to Add and Remove Packages
Running
make
orcs70-make
after you've coded each function will make it easier to narrow down (and fix!) any errors or warnings you get from the compiler—if the only new code is the code you're working on right now, you can have a pretty good idea where to start looking.
Car::addPackage()
-
Set the first
false
position ofbins_
to betrue
, simulating the addition of a package. This should also increment the value ofbinsInUse_
.- Hint: To find the location of the first
false
value, do you actually need to write a loop? How could the value ofbinsInUse_
help? - Note that people are not allowed to call
addPackage()
when a car is full.
- Hint: To find the location of the first
What should we do if people break the rules and try to add a package to a full car?
People aren't supposed to break the rules. If they do, the result is “undefined behavior”.
Okay, sure, but what should I do for my “undefined behavior”?
It's up to you. We recommend one of three choices:
- Don't check. Whatever happens, happens; probably an array out-of-bounds access will occur. Not checking maximizes execution speed, but causes usage errors to go undetected. On the positive side, if you don't write any code to check for improper use, the checking code can't be buggy.
- Check
isFull()
and throw astd::length_error
exception if needed. This approach detects improper usage at the cost of a few nanoseconds of execution time. (Requires#include <stdexcept>
.) -
Use an assertion. In this case, the assertion would be
assert(!isFull());
This code will abort the program with an error message if the condition
!isFull()
is false. This approach has the advantage that it's just one line of code, and if people need maximum speed in production code, checking of assertions can be turned off with a compiler option. (Requires#include <cassert>
.)
Car::removePackage()
-
Set the last
true
position ofbins_
to befalse
, simulating the removal of a package. This function should also decrement the value ofbinsInUse_
.- Hint: Similar to above, to find the location of the last
true
value, do you actually need to write a loop? - Note that people are not allowed to call
removePackage()
when a car is empty.
- Hint: Similar to above, to find the location of the last
If anyone breaks the rules, I'll erase all their files! Undefined behavior FTW!
No, we don't do things like that.
Yeah, but I do. So look out, rulebreakers!
Implement Printing for Car
Objects
operator<<
You already implemented operator<<
for the Car
class in Part 3 so there should be nothing to do for this function.
Hold your horses, I still don't get it. What's the deal with
operator<<
? Why does it return anostream&
and why is it always the same one that was passed in? What use is that?Okay, let's go through it one more time.
Review: The <<
Operator
When we write
cout << "My car is: " << myCar << endl;
it's the same as writing
((cout << "My car is: ") << myCar) << endl;
// ^^^^^^^^^^^^^^^^^^^^ ----------------------- this expression returns cout
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------ and this one does, too
And that code has the same result as writing
cout << "My car is: ";
cout << myCar;
cout << endl;
which explains why implementations of operator<<
for output streams always return the output stream. Our implementations of operator<<
just call our printToStream
member function, so our original code,
cout << "My car is: " << myCar << endl;
ends up being the equivalent of
cout << "My car is: ";
myCar.printToStream(cout);
cout << endl;
printToStream
Now you need to actually implement printToStream
. It will output a text representation of the Car
to the provided stream.
First, replace your stub code with something like
void Car::printToStream(std::ostream& outStream) const {
outStream << "[mystery car]";
}
and confirm everything still compiles.
Now, replace that dummy implementation that outputs [mystery car]
to the output stream with the real code. Here's pseudocode for what needs to be done:
- loop over
bins_
- if the bin is occupied
- output
[x]
- output
- if the bin is not occupied
- output
[_]
- output
- if the bin is occupied
- output a
~
to represent the connector to the next car - DO NOT output a newline/
endl
!
Thus a car with three occupied bins followed by one unoccupied one would send [x][x][x][_]~
to the output stream.
Remember, all output is sent to outStream
, not cout
.
(When logged in, completion status appears here.)