#include <iostream>
#include <cstdlib>
using std::cout;
using std::endl;

class BankAccount {
public:
	BankAccount(double balance) : balance(balance) {}
	~BankAccount() {}
	
	const double &getBalance() const { return balance; }
	const double &deposit(double amt) { return (balance += amt); }
	virtual const double &withdraw(double amt) {
		if (amt > balance) {
			exit(EXIT_FAILURE);
		}
		else {
			return (balance -= amt);
		}
	}
protected:
	double balance;
};

class SavingsAccount : public BankAccount {
public:
	/* rate must be set in an initializer since it is a const */
	SavingsAccount(double balance, double rate) :
		BankAccount(balance), rate(rate) {}
	~SavingsAccount() {}
	
	const double& accrueInterest() { return (balance *= (1.0+rate)); }

private:
	const double rate;
};

class ATMAccount : public BankAccount {
public:
	ATMAccount( double balance ) : BankAccount( balance ) {}
	~ATMAccount() {}
	
	/* withdraw method overloaded in derived class */
	virtual const double &withdraw(double amt) {
		if (amt + fee > balance) {
			exit(EXIT_FAILURE);
		}
		else {
			return (balance -= (amt+fee));
		}
	}

private:
	/* static since all ATM fees will be the same */
	static const double fee = 1.0;
}; 

int main()
{
	BankAccount Sally( 42.0 );
	SavingsAccount Jill( 73.0 , 0.004166 );
	ATMAccount Ralph( 400.0 );
	
	/* behavior is fine for calling withdraw method in all three cases */
	cout << Sally.withdraw( 10 ) << endl;
	cout << Jill.withdraw( 10 ) << endl;
	cout << Ralph.withdraw( 10 ) << endl;
	cout << endl;
	
	/* we can use pointers to base class to point to derived classes */
	BankAccount *a1 = &Sally;
	BankAccount *a2 = &Jill;
	BankAccount *a3 = &Ralph;
	
	/* now see what happens -- withdraw $10 from each account */
	cout << a1->withdraw( 10 ) << endl;
	cout << a2->withdraw( 10 ) << endl;
	cout << a3->withdraw( 10 ) << endl;

	return 0;
}