Final project: a catalog and a warehouse
A class in a real program usually rests on several ideas at once. For example, it keeps data in a container, takes text and checks whether an operation is allowed. The two exercises of the final project work the same way: they introduce no new constructs; you only combine familiar ones.
Two exercises
The catalog keeps books—Book structs with a number, a title, an author and a lent-out flag. It finds an author's books, lends a book out by its number and takes it back. The warehouse counts how many units of each item it holds. An item may be a string, a number or a value of another type, so the warehouse is a class template.
| Exercise | What it needs |
|---|---|
| Book catalog | a class, const methods, std::vector, std::string and std::string_view |
| Generic warehouse | a class template, a const method, std::map |
An operation can be impossible: lending a book that is already lent out, or taking more than there is. Then the method returns false and changes nothing.
How to proceed
Start with the fields and the add method: without them, the other methods have nothing to work with. Then write one method at a time and run the tests after each. The tests call the methods in turn, and the result of a call depends on the calls before it. So fix the first failed check: the ones after it often fail because of it.
Reading a check
A check that passes prints nothing. A check that fails prints a line marked ✗—this is how the warehouse stub answers the first check:
✗ fruit.count("apple") == 8 got: -1Left of == is the call from the test, and right of it is the expected value. After got: comes what your code returned. Here -1 comes from the stub: the count method is not written yet. Below the line are the test file's name and the line where the check is written.
A check of a condition, such as ✗ fruit.take("apple", 6), has no got: part: the condition turned out false, so take returned false. The summary "Passed n of m" shows how many checks passed. If the program stops abnormally, the line "During check" names the check where it happened.
Common mistake
A range-for loop changes the elements of a vector, but the loop variable is declared without &:
#include <iostream>
#include <vector>
struct Book {
int id;
bool lent = false;
};
int main() {
std::vector<Book> books{{1}, {2}};
for (Book book : books) { // ✗
book.lent = true;
}
std::cout << books[0].lent << ' ' << books[1].lent << '\n'; // 0 0
}The program builds and prints 0 0: on each iteration, book is a copy of the element, and the copy gets true. In the catalog, the tests reveal this mistake: lending the same book a second time returns true again. Declare the loop variable as a reference: for (Book& book : books). Then the loop changes the elements themselves, and the program prints 1 1.