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
BankErrorfromruntime_error, andInvalidAmountandNotEnoughfromBankError. - An amount of 0 or less throws
InvalidAmountwith the messageinvalid amount X. - A withdrawal larger than the balance throws
NotEnoughwith the messagenot enough money: balance B, asked X. - Catch
NotEnoughfirst and printrefused:and the message. CatchBankErrornext and printerror:and the message. After each successful command, printbalance 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
4 deposit 100 withdraw 30 withdraw 100 deposit -5
balance 100 balance 70 refused: not enough money: balance 70, asked 100 error: invalid amount -5
1 withdraw 1
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;
}