Перейти к содержимому
Теория · Итоговый проект · урок 1 из 3

Итоговый проект: каталог и склад

Класс в настоящей программе обычно опирается сразу на несколько идей. Например, он хранит данные в контейнере, принимает текст и проверяет, допустима ли операция. Две задачи итогового проекта устроены так же: новых конструкций в них нет, нужно соединить знакомые.

Две задачи

Каталог хранит книги — структуры Book с номером, названием, автором и отметкой о выдаче. Он находит книги автора, выдаёт книгу по номеру и принимает её обратно. Склад считает, сколько единиц каждого товара на нём лежит. Товаром может быть строка, число или значение другого типа, поэтому склад — шаблон класса (class template).

ЗадачаЧто понадобится
Каталог книгкласс, const-методы, std::vector, std::string и std::string_view
Обобщённый складшаблон класса, const-метод, std::map

Если операцию выполнить нельзя — выдать уже выданную книгу или забрать больше, чем есть, — метод возвращает false и ничего не меняет.

Порядок работы

Начните с полей (data members) и метода add: без них остальным методам не с чем работать. Затем пишите по одному методу и после каждого запускайте тесты. Тесты вызывают методы по очереди, и результат вызова зависит от предыдущих вызовов. Поэтому исправляйте первую непройденную проверку: следующие часто не проходят из-за неё.

Как читать проверку

Пройденная проверка ничего не печатает. Непройденная печатает строку со значком ✗ — так заготовка склада отвечает на первую проверку:

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

Слева от == стоит вызов из теста, справа — ожидаемое значение, а после got: — то, что вернул ваш код. Здесь -1 пришло из заготовки: метод count ещё не написан. Под строкой указаны файл с тестами и номер строки, где записана проверка.

У проверки условия, например ✗ fruit.take("apple", 6), части got: нет: условие оказалось ложным, то есть take вернул false. Сводка «Пройдено n из m» показывает, сколько проверок прошло. Если программа остановилась аварийно, строка «Во время проверки» назовёт проверку, на которой это случилось.

Частая ошибка

Цикл по диапазону (range-for) меняет элементы вектора, а переменная цикла объявлена без &:

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
}

Программа собирается и выводит 0 0: на каждой итерации book — копия элемента, и true получает копия. В каталоге такая ошибка видна по тестам: повторная выдача той же книги снова возвращает true. Объявите переменную цикла ссылкой (reference): for (Book& book : books). Тогда цикл изменит сами элементы, и программа выведет 1 1.