Мета та підготовка
Створити тип, який підтримує коректний стан через конструктор і публічні операції. Потрібно знати class, private, const метод і виняток. Використайте C++20 compiler. Створіть resource-class/main.cpp; збірка: c++ -std=c++20 -Wall -Wextra -pedantic main.cpp -o lab. Після збірки запустіть ./lab або відповідний exe.
Теоретичний мінімум
Інваріант класу задає властивість кожного коректного доступного стану. Демонстраційний лічильник обладнання має додатну місткість та залишок від нуля до місткості. Операція видачі зменшує залишок лише за його додатності. Операція повернення збільшує лише до місткості. Нормальна відмова не повинна змінювати стан.
Конструктор встановлює початкову кількість. Приватні поля не доступні для довільного зовнішнього запису, тому всі зміни проходять через перевірені методи. Метод читання має const, щоб його можна було викликати для незмінного об’єкта. Повернення bool показує успішність операції; це погоджений контракт, який потрібно перевіряти у викликача.
Повний демонстраційний код
#include <cassert>
#include <iostream>
#include <stdexcept>
class Stock {
int capacity_;
int available_;
public:
explicit Stock(int capacity) : capacity_(capacity), available_(capacity) {
if (capacity <= 0) throw std::invalid_argument("capacity");
}
int available() const { return available_; }
bool borrow() {
if (available_ == 0) return false;
--available_;
return true;
}
bool give_back() {
if (available_ == capacity_) return false;
++available_;
return true;
}
};
int main() {
Stock stock{2};
assert(stock.borrow());
assert(stock.borrow());
assert(!stock.borrow());
assert(stock.available() == 0);
assert(stock.give_back());
assert(stock.available() == 1);
std::cout << "available=" << stock.available() << '\n';
}
Очікується available=1. Дві видачі переходять із 2 до 0, третя повертає false без зміни. Повернення переводить стан до 1. explicit не дозволяє довільне неявне створення Stock із числа в контекстах, де це могло б приховати дію. Деструктор не потрібний, оскільки клас не керує сирим ресурсом: його стан складається з цілих значень.
Покрокове виконання
Запишіть інваріант нерівністю . Складіть таблицю переходів для двох видач і трьох повернень. Виконайте її на папері, потім додайте відповідні assert. Перевірте конструктор з нулем і від’ємною місткістю через try/catch. Після кожної відмови порівняйте залишок із попереднім станом.
Поясніть, чому недостатньо зробити поля private без перевірок у borrow та give_back. Додайте const об’єкт і продемонструйте доступ до available без зміни стану. Не перевіряйте приватні поля через порушення доступу; спостерігайте поведінку публічного контракту. Це залишає тести корисними після зміни внутрішнього представлення.
Самостійне завдання
Спроєктуйте клас резервування навчальної аудиторії або видачі конкретної одиниці обладнання. Додайте непорожній ідентифікатор, визначений набір станів та операції, які зберігають правила переходів. Потрібно мати щонайменше дві допустимі й дві відхилені зміни, а також перевірки конструктора.
Самостійно визначте інтерфейс і реакцію на помилки. Окремо поясніть, чи об’єкт можна копіювати за змістом предметної області. Копія стану видачі не повинна випадково означати появу другого фізичного пристрою. Демонстрація лічильника показує механізм інваріанта; ідентичність і правила вашого об’єкта потрібно розробити самостійно.
Варіант розвитку
Додайте групу об’єктів у vector і функцію пошуку за ID. Уточніть унікальність і час життя результату пошуку. Якщо повертаєте посилання на елемент, поясніть операції, які можуть його інвалідувати. Для невеликого звіту можна повернути незалежне значення з потрібними характеристиками, не відкриваючи весь внутрішній стан.
Типові помилки та налагодження
Помилки: перевірка після зменшення лічильника, дозволений нульовий capacity, забута верхня межа повернення та змінюваний геттер. Збій відтворюйте короткою послідовністю операцій. Запишіть стан до й після кожної дії. Якщо порушено інваріант, знайдіть першу операцію, після якої він перестав виконуватися.
Очікуваний результат і контрольні питання
Подайте код, опис інваріанта, таблицю переходів і результати тестів. Поясніть, що гарантує конструктор і що залишається істинним при відмові. Чому тести мають перевіряти публічну поведінку? Як копіювання впливає на предметну ідентичність? Які результати можна безпечно повертати за значенням?
Таблиця станів та перевірка відмови
Для Stock випишіть послідовність remaining: початкове значення, успішне отримання, повернення, повторне повернення біля максимальної місткості. Кожен перехід повинен зберігати діапазон від нуля до capacity. Якщо метод повертає false, стан має залишитися попереднім. Перевіряйте цю постумову окремим читанням.
Для власного Equipment визначте, що означає ідентичність. Два об’єкти з однаковою назвою можуть бути різними фізичними пристроями, тому інвентарний номер потребує власного правила. Копіювання опису в пам’яті не повинне випадково створювати другий фізичний ресурс у предметній моделі; поясніть політику у звіті.
Створіть негативні сценарії конструктора: порожня назва, некоректна місткість або невідомий стан за вашими вимогами. У кожному випадку покажіть, що неприпустимий об’єкт не став доступним клієнту. Для методів перевірте граничний ресурс з місткістю один: він швидко виявляє помилки на останній одиниці.
Не робіть поля публічними для спрощення тесту. Виводьте стан через допустимі спостережувані методи й виконуйте зміни через предметні операції. У висновку пов’яжіть інваріант з усіма місцями, де він перевіряється. Сам список private-полів не пояснює, як клас забезпечує узгоджену поведінку під час кожного виклику.
Схема процесу
Встановлюємо допустиму місткість.
Самоперевірка
Як обґрунтувати відповідь своїми словами?
Підсумок
Клас підтримує інваріант через обмежений публічний контракт. Відмова має визначений наслідок для стану. Тести поведінки й аналіз ідентичності допомагають створювати осмислені об’єктні моделі.