Skip to content
Theory · Final Project · lesson 1 of 3

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.

ExerciseWhat it needs
Book cataloga class, const methods, std::vector, std::string and std::string_view
Generic warehousea 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:

TEXT
✗ fruit.count("apple") == 8   got: -1

Left 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 &:

C++
#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.