C++: Your own exception classes

Design a small family of exception classes, and catch them from the most specific to the most general.

What to build

An account whose deposit and withdraw throw exceptions of your own types, caught in the right order.

Requirements

  • Derive BankError from runtime_error, and InvalidAmount and NotEnough from BankError.
  • An amount of 0 or less throws InvalidAmount with the message invalid amount X.
  • A withdrawal larger than the balance throws NotEnough with the message not enough money: balance B, asked X.
  • Catch NotEnough first and print refused: and the message. Catch BankError next and print error: and the message. After each successful command, print balance B.

Input

The first line has q. Each of the next q lines is deposit x or withdraw x.

Output

One line per command.

Constraints

1 ≤ q ≤ 100, and amounts are whole numbers from -1000000 to 1000000. The balance starts at 0.

Example

Input:

4
deposit 100
withdraw 30
withdraw 100
deposit -5

Output:

balance 100
balance 70
refused: not enough money: balance 70, asked 100
error: invalid amount -5

Why it works

A catch for a base class also matches its derived classes, so the order of the catch blocks decides which one runs. Putting the specific class first gives it its own message, and the base class catches the rest.

Examples

Example 1 · Input
4
deposit 100
withdraw 30
withdraw 100
deposit -5
Expected output
balance 100
balance 70
refused: not enough money: balance 70, asked 100
error: invalid amount -5
Example 2 · Input
1
withdraw 1
Expected output
refused: not enough money: balance 0, asked 1

Hints

Hint 1

`class BankError : public runtime_error` with a constructor that passes the message on: `BankError(const string& m) : runtime_error(m) {}`.

Hint 2

Derive `InvalidAmount` and `NotEnough` from `BankError`, and build their messages with `to_string`.

Hint 3

Catch `NotEnough` before `BankError`, because the first matching catch wins.

Solution

Show one correct solution (try it yourself first)
#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;

class BankError : public runtime_error {
public:
    BankError(const string& m) : runtime_error(m) {}
};

class InvalidAmount : public BankError {
public:
    InvalidAmount(int x) : BankError("invalid amount " + to_string(x)) {}
};

class NotEnough : public BankError {
public:
    NotEnough(int balance, int x) : BankError("not enough money: balance " + to_string(balance) + ", asked " + to_string(x)) {}
};

class Account {
    int balance;
public:
    Account() : balance(0) {}
    void deposit(int x) {
        if (x <= 0) throw InvalidAmount(x);
        balance += x;
    }
    void withdraw(int x) {
        if (x <= 0) throw InvalidAmount(x);
        if (x > balance) throw NotEnough(balance, x);
        balance -= x;
    }
    int getBalance() const { return balance; }
};

int main() {
    int q;
    cin >> q;
    Account acc;
    while (q-- > 0) {
        string cmd;
        int x;
        cin >> cmd >> x;
        try {
            if (cmd == "deposit") acc.deposit(x);
            else acc.withdraw(x);
            cout << "balance " << acc.getBalance() << endl;
        } catch (const NotEnough& e) {
            cout << "refused: " << e.what() << endl;
        } catch (const BankError& e) {
            cout << "error: " << e.what() << endl;
        }
    }
    return 0;
}

Lesson: Exceptions →