Next, consider the BrassPlus::Withdraw() method. If the client withdraws an amount larger than the balance, the method should arrange for a loan. It can use Brass::Withdraw() to access the balance member, but Brass::Withdraw() issues an error message if the withdrawal amount exceeds the balance. This implementation avoids the message by using the Deposit() method to make the loan and then calling Brass::Withdraw() when sufficient funds are available:
// redefine how Withdraw() works
void BrassPlus::Withdraw(double amt)
{
...
double bal = Balance();
if (amt <= bal)
Brass::Withdraw(amt);
else if ( amt <= bal + maxLoan - owesBank)
{
double advance = amt - bal;
owesBank += advance * (1.0 + rate);
cout << "Bank advance: $" << advance << endl;
cout << "Finance charge: $" << advance * rate << endl;
Deposit(advance);
Brass::Withdraw(amt);
}
else
cout << "Credit limit exceeded. Transaction cancelled.\n";
...
}
Note that the method uses the base-class Balance() function to determine the original balance. The code doesn’t have to use the scope-resolution operator for Balance() because this method has not been redefined in the derived class.
The ViewAcct() and the Withdraw() methods use the setf() and precision() formatting methods to set the output mode for floating-point values to fixed-point, two places to the right of the decimal. When these modes are set, output stays in that mode, so the polite thing for these methods to do is to reset the formatting mode to its state prior to calling the methods. Listings 8.8 and 10.5 use similar approaches. To avoid some code duplication, the program moves some of the formatting actions to helper functions:
// formatting stuff
typedef std::ios_base::fmtflags format;
typedef std::streamsize precis;
format setFormat();
void restore(format f, precis p);
The setFormat() function sets fixed-point notation and returns the previous flag setting:
format setFormat()
{
// set up ###.## format
return cout.setf(std::ios_base::fixed,
std::ios_base::floatfield);
}
And the restore() function resets the format and the precision:
void restore(format f, precis p)
{
cout.setf(f, std::ios_base::floatfield);
cout.precision(p);
}
You can find more details about formatting in Chapter 17, “Input, Output, and Files.”
Using the Brass and BrassPlus Classes
Listing 13.9 shows the class definitions with a Brass object and a BrassPlus object.
Listing 13.9. usebrass1.cpp
// usebrass1.cpp -- testing bank account classes
// compile with brass.cpp
#include
#include "brass.h"
int main()
{
using std::cout;
using std::endl;
Brass Piggy("Porcelot Pigg", 381299, 4000.00);
BrassPlus Hoggy("Horatio Hogg", 382288, 3000.00);
Piggy.ViewAcct();
cout << endl;
Hoggy.ViewAcct();
cout << endl;
cout << "Depositing $1000 into the Hogg Account:\n";
Hoggy.Deposit(1000.00);
cout << "New balance: $" << Hoggy.Balance() << endl;
cout << "Withdrawing $4200 from the Pigg Account:\n";
Piggy.Withdraw(4200.00);
cout << "Pigg account balance: $" << Piggy.Balance() << endl;
cout << "Withdrawing $4200 from the Hogg Account:\n";
Hoggy.Withdraw(4200.00);
Hoggy.ViewAcct();
return 0;
}
In the following output of the program in Listing 13.9, note that Hogg gets overdraft protection and Pigg does not:
Client: Porcelot Pigg
Account Number: 381299
Balance: $4000.00
Client: Horatio Hogg
Account Number: 382288
Balance: $3000.00
Maximum loan: $500.00
Owed to bank: $0.00
Loan Rate: 11.125%
Depositing $1000 into the Hogg Account:
New balance: $4000
Withdrawing $4200 from the Pigg Account:
Withdrawal amount of $4200.00 exceeds your balance.
Withdrawal canceled.
Pigg account balance: $4000
Withdrawing $4200 from the Hogg Account:
Bank advance: $200.00
Finance charge: $22.25
Client: Horatio Hogg
Account Number: 382288
Balance: $0.00
Maximum loan: $500.00
Owed to bank: $222.25
Loan Rate: 11.125%
Showing Virtual Method Behavior
In Listing 13.9 the methods are invoked by objects, not pointers or references, so this program doesn’t use the virtual method feature. Let’s look at an example for which the virtual methods do come into play. Suppose you would like to manage a mixture of Brass and BrassPlus accounts. It would be nice if you could have a single array that holds a mixture of Brass and BrassPlus objects, but that’s not possible. Every item in an array has to be of the same type, and Brass and BrassPlus are two separate types. However, you can create an array of pointers-to-Brass. In that case, every element is of the same type, but because of the public inheritance model, a pointer-to-Brass can point to either a Brass or a BrassPlus object. Thus, in effect, you have a way of representing a collection of more than one type of object with a single array. This is polymorphism, and Listing 13.10 shows a simple example.
Listing 13.10. usebrass2.cpp
// usebrass2.cpp -- polymorphic example
// compile with brass.cpp
#include
#include
#include "brass.h"
const int CLIENTS = 4;
int main()
{
using std::cin;
using std::cout;
using std::endl;