Module 2 — Lab 2: the same program, with types¶
Levels: [L2 Apply → L4 Analyze] · Extends: Lab 1 — the procedural baseline · Time: 3–4 hours
Where each lab's brief lives
Every lab brief is published with the module that teaches its technique, so Lab 1's is on Module 1's page. The index of all sixteen is Labs.
The scenario¶
The lending desk from Lab 1 is working — the assistant can add an item, lend it, take it back, and print the catalogue. The library has now asked for two things at once:
- borrowers must be recorded. Not just "this item is out", but who has it.
- a limit per borrower. No member may hold more than three items at a time.
You still have the Lab 1 program, and you have just read Module 2. This lab is the direct comparison: the same behaviour, built from types instead of parallel arrays.
★ Keep Lab 1's file. You will compare them at the end. The comparison is a deliverable, and it is where the learning is — not in the finished program, which any competent programmer could write.
What you start from¶
Your Lab 1 program: parallel global arrays, free functions taking arrays or counts, a
menu loop reading A, L, R, P, Q. If yours is lost, rebuild a smaller version
(one array each for identifiers, titles and the on-loan flag) — do not start from the
reference solution, because the comparison needs your baseline.
The command set grows by one, for members:
| Command | Meaning |
|---|---|
A <id> <title> |
add an item with that identifier and title |
M <name> |
add a member |
L <id> <member> |
lend item <id> to <member> |
R <id> |
take it back |
P |
print items and members |
Q |
quit (or just end the input) |
Reading commands works exactly as it did in Lab 1: whole lines, then
std::istringstream, with std::getline for the free-text part. That pattern is in
examples/labs/lab-02/solution/main.cpp and is worth keeping in your own style —
it is how every later lab's test session is scripted.
Requirements¶
- Three types:
Book,Member,Catalogue. Not two, not five. Each gets the operations it needs and nothing else. - All data members
private. Not "because the lab says so" — because the caller should not be able to write to them. conston every member function that does not modify the object. The print functions must be able to take aconst Catalogue&.- A header and a source file for the types, with
mainin its own file. Build all three with one command:g++ -std=c++17 -Wall -Wextra main.cpp library.cpp -o library - Member operations, not field access.
Booklends and returns itself (lend(),giveBack()), andMemberrecords and releases its own borrowings. No getter or setter may exist merely because there is a field behind it. - The per-member limit of three, enforced by
Member, not by the caller. - Every operation that can fail says which failure it was, or refuses cleanly. The deliberate flaw Lab 1 required — two different failures reported identically — must be gone in this version.
- No warnings, and a scripted session that exercises every command at least once.
- The comparison table described under What to deliver.
Requirement 5 is the one people fail
"No getter or setter merely because there is a field behind it" is a real design
constraint, and it is the difference between this lab being an exercise in syntax
and an exercise in design. A Book that exposes setOnLoan(bool) has taken the
rule out of the class and handed it back to the caller — which is exactly Lab 1's
problem wearing a class keyword.
What to deliver¶
The working program, plus:
- The comparison table. Fill it in by measurement, not memory:
| Lab 1 (arrays) | Lab 2 (types) | |
|---|---|---|
Places that had to change to add publicationYear |
||
Places that had to change to add Member |
||
| Functions that took a data parameter they did not use | ||
| Rules enforced in exactly one place | ||
| Rules no longer enforced anywhere |
- An interface table, one row per public member of each type: the promise it makes, and why it is public. This is Lab 4's full deliverable in miniature, and doing it now makes that lab short. Two example rows:
| Member | The promise | Why public |
|---|---|---|
bool lend() |
Marks the book out, or changes nothing and returns false | The system's own verb; a caller cannot express "mark it out when it is already out" |
int id() const |
The identity, which never changes | Items are referred to by identifier everywhere |
- Three or four sentences on what you gave up. The class version is not free: list the things Lab 1 could do that Lab 2 now prevents, and say for each whether the change is a gain or a loss.
Self-assessment checklist¶
Run it honestly. There is no marker in self-study, and this is the checklist a marker would use.
It builds and runs
- [ ]
g++ -std=c++17 -Wall -Wextra main.cpp library.cpp -o libraryproduces no warnings - [ ] The program is in three files at minimum, and
mainincludes only the header - [ ] All six commands work, including
Mand the newL <id> <member> - [ ] An unknown command, a bad identifier and a missing name each produce a message, not a crash
It is designed
- [ ] Every data member is
privatein all three types - [ ] Every member function that does not modify the object is
const - [ ] The limit of three is enforced inside
Member, and there is no way to set it from outside - [ ] No public member exists solely to read or write a field
- [ ] Each type's responsibility fits in one sentence without "and"
It is correct
- [ ] Lending an item that is already out is refused, and both the item and the member are unchanged
- [ ] Returning an item the member does not hold is refused, and the count stays right
- [ ] The fourth item for one member is refused, while another member can still borrow
- [ ] Boundary cases work: no items, no members, one member, a duplicate identifier
- [ ] The two-failure conflation Lab 1 required is gone — each refusal says which failure it was
It is explained
- [ ] The comparison table is filled in with measured numbers
- [ ] The interface table covers every public member of all three types
- [ ] The "what you gave up" note names specific losses, not generalities
- [ ] You can point at the one line where each invariant is enforced
Common ways this lab goes wrong¶
| Symptom | Cause | Fix |
|---|---|---|
undefined reference to Book::Book(int, const std::string&) |
The constructor is declared in the header and not defined in the source file | That is the module's signature error. Run the declaration/definition check — Debugging |
error: redefinition of 'class Book' |
Header included twice, or no #pragma once |
First line of the header |
| Everything is in one file "for now" | The file split was treated as optional | Requirement 4 is not cosmetic: Lab 16 is a multi-file project, and Lab 3 onwards assumes you can build three files without thinking |
| Every field has a getter and a setter | The class is a container, not a promise | Re-read M3 in Misconceptions and delete the accessors nothing needs |
printCatalogue(catalogue) does not compile |
A non-const member function is being called on a const Catalogue& |
Mark the observing member functions const — the error is the compiler pointing at the promise you forgot to make |
| The member count is stored and the books are stored, and they disagree | Two sources of truth | Derive the count from the collection. See examples/labs/lab-04/solution/justification.md on why one source of truth removed the most bugs |
| The session in the README does not match the program | The output was written from memory | Re-run the scripted session and capture, exactly as the repository does for its own examples |
Reference solution¶
examples/labs/lab-02/solution/ — library.h, library.cpp, main.cpp.
Build and try it exactly as the lab requires:
g++ -std=c++17 -Wall -Wextra main.cpp library.cpp -o library
./library <<'EOF'
A 1001 C++ Primer
A 1002 Clean Code
M Alice
M Bilal
L 1001 Alice
L 1002 Alice
P
L 1002 Bilal
R 1001
P
EOF
Read it after your own version runs. Two things to compare in particular:
- What it does not have. No
setTitle, nosetOnLoan, nogetBooks. That absence is the design. - What it leaks anyway.
Catalogue::find(int)returns a mutableBook*. That is a real weakness, deliberately left in so that Challenge X2 has something to find — and a thing to look for in your own solution.
Next: Challenge problems — interface design on paper, and the leaks in the reference solution. · All modules