cout << "Negative deposit not allowed; "
<< "deposit is cancelled.\n";
else
balance += amt;
}
void Brass::Withdraw(double amt)
{
// set up ###.## format
format initialState = setFormat();
precis prec = cout.precision(2);
if (amt < 0)
cout << "Withdrawal amount must be positive; "
<< "withdrawal canceled.\n";
else if (amt <= balance)
balance -= amt;
else
cout << "Withdrawal amount of $" << amt
<< " exceeds your balance.\n"
<< "Withdrawal canceled.\n";
restore(initialState, prec);
}
double Brass::Balance() const
{
return balance;
}
void Brass::ViewAcct() const
{
// set up ###.## format
format initialState = setFormat();
precis prec = cout.precision(2);
cout << "Client: " << fullName << endl;
cout << "Account Number: " << acctNum << endl;
cout << "Balance: $" << balance << endl;
restore(initialState, prec); // restore original format
}
// BrassPlus Methods
BrassPlus::BrassPlus(const string & s, long an, double bal,
double ml, double r) : Brass(s, an, bal)
{
maxLoan = ml;
owesBank = 0.0;
rate = r;
}
BrassPlus::BrassPlus(const Brass & ba, double ml, double r)
: Brass(ba) // uses implicit copy constructor
{
maxLoan = ml;
owesBank = 0.0;
rate = r;
}
// redefine how ViewAcct() works
void BrassPlus::ViewAcct() const
{
// set up ###.## format
format initialState = setFormat();
precis prec = cout.precision(2);
Brass::ViewAcct(); // display base portion
cout << "Maximum loan: $" << maxLoan << endl;
cout << "Owed to bank: $" << owesBank << endl;
cout.precision(3); // ###.### format
cout << "Loan Rate: " << 100 * rate << "%\n";
restore(initialState, prec);
}
// redefine how Withdraw() works
void BrassPlus::Withdraw(double amt)
{
// set up ###.## format
format initialState = setFormat();
precis prec = cout.precision(2);
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";
restore(initialState, prec);
}
format setFormat()
{
// set up ###.## format
return cout.setf(std::ios_base::fixed,
std::ios_base::floatfield);
}
void restore(format f, precis p)
{
cout.setf(f, std::ios_base::floatfield);
cout.precision(p);
}
Before looking at details of Listing 13.8, such as handling of formatting in some of the methods, let’s examine the aspects that relate directly to inheritance. Keep in mind that the derived class does not have direct access to private base-class data; the derived class has to use base-class public methods to access that data. The means of access depends on the method. Constructors use one technique, and other member functions use a different technique.
The technique that derived-class constructors use to initialize base-class private data is the member initializer list syntax. The RatedPlayer class constructors use that technique, and so do the BrassPlus constructors:
BrassPlus::BrassPlus(const string & s, long an, double bal,
double ml, double r) : Brass(s, an, bal)
{
maxLoan = ml;
owesBank = 0.0;
rate = r;
}
BrassPlus::BrassPlus(const Brass & ba, double ml, double r)
: Brass(ba) // uses implicit copy constructor
{
maxLoan = ml;
owesBank = 0.0;
rate = r;
}
Each of these constructors uses the member initializer list syntax to pass base-class information to a base-class constructor and then uses the constructor body to initialize the new data items added by the BrassPlus class.
Non-constructors can’t use the member initializer list syntax. But a derived-class method can call a public base-class method. For instance, ignoring the formatting aspect, the core of the BrassPlus version of ViewAcct() is this:
// redefine how ViewAcct() works
void BrassPlus::ViewAcct() const
{
...
Brass::ViewAcct(); // display base portion
cout << "Maximum loan: $" << maxLoan << endl;
cout << "Owed to bank: $" << owesBank << endl;
cout << "Loan Rate: " << 100 * rate << "%\n";
...
}
In other words, BrassPlus::ViewAcct() displays the added BrassPlus data members and calls on the base-class method Brass::ViewAcct() to display the base-class data members. Using the scope-resolution operator in a derived-class method to invoke a base-class method is a standard technique.
It’s vital that the code use the scope-resolution operator. Suppose that, instead, you wrote the code this way:
// redefine erroneously how ViewAcct() works
void BrassPlus::ViewAcct() const
{
...
ViewAcct(); // oops! recursive call
...
}
If the code doesn’t use the scope-resolution operator, the compiler assumes that ViewAcct() is BrassPlus::ViewAcct(), and this creates a recursive function that has no termination—not a good thing.