Extend the library design with a new rule, and see how little of the code has to change.
What to build
A library that charges a fine for each day an item is kept past its loan period.
Requirements
- Support
add KIND Tforbook,dvdandmagazine, with loans of 14, 7 and 3 days and fines of 5, 10 and 2 per late day. lend Tprintslent T for N days.return T D, where D is the number of days the item was kept, printsreturned T, fine F.- Report an unknown title, lending an item that is out, and returning one that is in with exceptions, printing
sorry:with the message. - After the last command, print
fines total T. The library owns and deletes its items, and cannot be copied.
Input
The first line has q. Each of the next q lines is a command. Titles are single words.
Output
One line per lend, return or failed command, then fines total T.
Constraints
1 ≤ q ≤ 100, and 0 ≤ D ≤ 1000.
Example
Input:
6
add book Dune
add dvd Cosmos
lend Dune
lend Cosmos
return Dune 20
return Cosmos 7
Output:
lent Dune for 14 days
lent Cosmos for 7 days
returned Dune, fine 30
returned Cosmos, fine 0
fines total 30
Why it works
The new rule is one more virtual function. The library's code asks each item for its own fine, so it never needs to know which kind of item it is handling.
Examples
6 add book Dune add dvd Cosmos lend Dune lend Cosmos return Dune 20 return Cosmos 7
lent Dune for 14 days lent Cosmos for 7 days returned Dune, fine 30 returned Cosmos, fine 0 fines total 30
3 add magazine Time lend Time return Time 10
lent Time for 3 days returned Time, fine 14 fines total 14
Hints
Hint 1
Add a pure virtual `int finePerDay() const` beside `loanDays()`: 5 for a book, 10 for a DVD, 2 for a magazine.
Hint 2
On return, the days late are the days kept minus the loan period, and nothing if that is not positive.
Hint 3
Keep the running total of fines in the `Library`, and print it after the last command.
Solution
Show one correct solution (try it yourself first)
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
using namespace std;
class Item {
string title;
bool out;
public:
Item(string t) : title(t), out(false) {}
virtual ~Item() {}
string getTitle() const { return title; }
void borrow() {
if (out) throw runtime_error(title + " is already borrowed");
out = true;
}
int giveBack(int days) {
if (!out) throw runtime_error(title + " is not borrowed");
out = false;
int late = days - loanDays();
return late > 0 ? late * finePerDay() : 0;
}
virtual int loanDays() const = 0;
virtual int finePerDay() const = 0;
};
class Book : public Item {
public:
Book(string t) : Item(t) {}
int loanDays() const override { return 14; }
int finePerDay() const override { return 5; }
};
class DVD : public Item {
public:
DVD(string t) : Item(t) {}
int loanDays() const override { return 7; }
int finePerDay() const override { return 10; }
};
class Magazine : public Item {
public:
Magazine(string t) : Item(t) {}
int loanDays() const override { return 3; }
int finePerDay() const override { return 2; }
};
class Library {
vector<Item*> items;
int fines;
public:
Library() : fines(0) {}
Library(const Library&) = delete;
Library& operator=(const Library&) = delete;
~Library() {
for (Item* it : items) delete it;
}
void add(Item* it) { items.push_back(it); }
Item& find(const string& title) {
for (Item* it : items)
if (it->getTitle() == title) return *it;
throw invalid_argument("no item called " + title);
}
void lend(const string& title) {
Item& it = find(title);
it.borrow();
cout << "lent " << title << " for " << it.loanDays() << " days" << endl;
}
void takeBack(const string& title, int days) {
int fine = find(title).giveBack(days);
fines += fine;
cout << "returned " << title << ", fine " << fine << endl;
}
int totalFines() const { return fines; }
};
int main() {
int q;
cin >> q;
Library lib;
while (q-- > 0) {
string cmd, title;
cin >> cmd;
try {
if (cmd == "add") {
string kind;
cin >> kind >> title;
if (kind == "book") lib.add(new Book(title));
else if (kind == "dvd") lib.add(new DVD(title));
else lib.add(new Magazine(title));
} else if (cmd == "lend") {
cin >> title;
lib.lend(title);
} else {
int days;
cin >> title >> days;
lib.takeBack(title, days);
}
} catch (const exception& e) {
cout << "sorry: " << e.what() << endl;
}
}
cout << "fines total " << lib.totalFines() << endl;
return 0;
}