C++: A library that lends and takes back

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 T and add dvd T add an item. Books are lent for 14 days and DVDs for 7.
  • lend T prints lent T for N days, and return T prints returned 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.
  • list prints each item in the order added, as [out] T or [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

Example 1 · Input
6
add book Dune
add dvd Cosmos
lend Cosmos
lend Cosmos
return Dune
list
Expected output
lent Cosmos for 7 days
sorry: Cosmos is already borrowed
sorry: Dune is not borrowed
[in] Dune
[out] Cosmos
Example 2 · Input
1
lend Ghost
Expected output
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;
}

Lesson: Project: a small library system →