Put the design into practice: ownership, encapsulation and exceptions working together.
What to build
A Library class that adds items, lends them, takes them back and lists them, reporting every broken rule with an exception.
Requirements
add book Tandadd dvd Tadd an item. Books are lent for 14 days and DVDs for 7.lend Tprintslent T for N days, andreturn Tprintsreturned T.- Report an unknown title, lending an item that is out, and returning one that is in by throwing, and print
sorry:with the message. listprints each item in the order added, as[out] Tor[in] T.
Input
The first line has q. Each of the next q lines is a command. Titles are single words.
Output
One line for each lend, return and failed command, and one line per item for list.
Constraints
1 ≤ q ≤ 100.
Example
Input:
6
add book Dune
add dvd Cosmos
lend Cosmos
lend Cosmos
return Dune
list
Output:
lent Cosmos for 7 days
sorry: Cosmos is already borrowed
sorry: Dune is not borrowed
[in] Dune
[out] Cosmos
Why it works
Each item enforces its own rules, the library is the single owner that deletes the items, and exceptions carry each problem up to the one place that prints it.
Examples
6 add book Dune add dvd Cosmos lend Cosmos lend Cosmos return Dune list
lent Cosmos for 7 days sorry: Cosmos is already borrowed sorry: Dune is not borrowed [in] Dune [out] Cosmos
1 lend Ghost
sorry: no item called Ghost
Hints
Hint 1
`Library` owns a `vector<Item*>`, deletes them in its destructor, and forbids copying.
Hint 2
`find` returns a reference to the item, or throws `invalid_argument` for an unknown title.
Hint 3
`borrow` and `giveBack` in `Item` throw `runtime_error` when the item is already out, or is not out.
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; }
bool isOut() const { return out; }
void borrow() {
if (out) throw runtime_error(title + " is already borrowed");
out = true;
}
void giveBack() {
if (!out) throw runtime_error(title + " is not borrowed");
out = false;
}
virtual int loanDays() const = 0;
};
class Book : public Item {
public:
Book(string t) : Item(t) {}
int loanDays() const override { return 14; }
};
class DVD : public Item {
public:
DVD(string t) : Item(t) {}
int loanDays() const override { return 7; }
};
class Library {
vector<Item*> items;
public:
Library() {}
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) {
find(title).giveBack();
cout << "returned " << title << endl;
}
void list() const {
for (Item* it : items) cout << (it->isOut() ? "[out] " : "[in] ") << it->getTitle() << endl;
}
};
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 lib.add(new DVD(title));
} else if (cmd == "list") {
lib.list();
} else {
cin >> title;
if (cmd == "lend") lib.lend(title);
else lib.takeBack(title);
}
} catch (const exception& e) {
cout << "sorry: " << e.what() << endl;
}
}
return 0;
}