We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Const Correctness and Class Design step 3 of 3
The handle you left in the door
A class exists to hold something true. Ledger keeps a running total that
always equals the sum of its entries; SortedList stays sorted; Connection
is either open or closed and never both. That statement is the class’s
invariant, and it is the only reason to have a class rather than a
struct with some functions near it.
An invariant is only true if it cannot be broken from outside. Which makes the public section a promise about what callers are able to do:
Anything reachable from outside will eventually be used from outside. Not because your colleagues are careless, but because it is there, it compiles, and it was the shortest path to whatever they needed that day.
Where the hole usually is
Not in a public data member — those get caught in review. It is in the accessor:
std::vector<int>& entries() { return entries_; } // a hole
It reads like a getter. It hands out a non-const reference to the object’s
own storage, so every caller can push_back, clear, erase and sort the
internals while the class goes on believing its total is correct. The _
suffix and the private: above it bought nothing.
const std::vector<int>& entries() const { return entries_; } // a view
Two consts, and the accessor is now what it looked like all along.
The rule of thumb
| Ask | If yes |
|---|---|
| Does a caller need to read this? |
return const T& |
| Does a caller need to change this? | give them the operation, not the data |
| Neither? | it is private, and stays private |
The middle row is the one that takes discipline. A caller who wants to append
an entry does not need your vector; they need add(value) — a function that
can update the total, reject a bad input, and keep working when the storage
changes to something else next year. Every operation you expose is a decision
you can revisit. Every piece of data you expose is one you cannot.
And the smaller surface is also the cheaper one
Everything public is something you must keep working. A class with four
public functions has four things to get right in the next refactor; one that
also returns a mutable reference to a std::vector has committed to the
vector.
Your task
Ledger claims that total() is the sum of its entries. It is not, because
entries() hands out the vector and record uses it.
-
Close the hole:
entries()should return something a caller can only read. -
Give
recordthe operation it actually needed — anaddonLedgerthat keeps the total honest. -
Update
recordto use it. It is the caller that was reaching in, and once the hole is closed it will not compile as written.
The harness compares total() against the real sum of the entries.
Stuck?
C++ reference solution
Sign in to attempt this problem and reveal the reference solution.