void Deposit(double amt) ;

    virtual void Withdraw(double amt) = 0; // pure virtual function

    double Balance() const {return balance;};

    virtual void ViewAcct() const = 0;     // pure virtual function

    virtual ~AcctABC() {}

};

// Brass Account Class

class Brass :public AcctABC

{

public:

    Brass(const std::string & s = "Nullbody", long an = -1,

           double bal = 0.0) : AcctABC(s, an, bal) { }

    virtual void Withdraw(double amt);

    virtual void ViewAcct() const;

    virtual ~Brass() {}

};

//Brass Plus Account Class

class BrassPlus : public AcctABC

{

private:

    double maxLoan;

    double rate;

    double owesBank;

public:

    BrassPlus(const std::string & s = "Nullbody", long an = -1,

            double bal = 0.0, double ml = 500,

            double r = 0.10);

    BrassPlus(const Brass & ba, double ml = 500, double r = 0.1);

    virtual void ViewAcct()const;

    virtual void Withdraw(double amt);

    void ResetMax(double m) { maxLoan = m; }

    void ResetRate(double r) { rate = r; };

    void ResetOwes() { owesBank = 0; }

};

#endif

The next step is to implement the methods that don’t already have inline definitions. Listing 13.12 does that.

Listing 13.12. acctabc.cpp

// acctabc.cpp -- bank account class methods

#include

#include "acctabc.h"

using std::cout;

using std::ios_base;

using std::endl;

using std::string;

// Abstract Base Class

AcctABC::AcctABC(const string & s, long an, double bal)

{

    fullName = s;

    acctNum = an;

    balance = bal;

}

void AcctABC::Deposit(double amt)

{

    if (amt < 0)

        cout << "Negative deposit not allowed; "

             << "deposit is cancelled.\n";

    else

        balance += amt;

}

void AcctABC::Withdraw(double amt)

{

    balance -= amt;

}

// protected methods for formatting

AcctABC::Formatting AcctABC::SetFormat() const

{

 // set up ###.## format

    Formatting f;

    f.flag =

        cout.setf(ios_base::fixed, ios_base::floatfield);

    f.pr = cout.precision(2);

    return f;

}

void AcctABC::Restore(Formatting & f) const

{

    cout.setf(f.flag, ios_base::floatfield);

    cout.precision(f.pr);

}

// Brass methods

void Brass::Withdraw(double amt)

{

    if (amt < 0)

        cout << "Withdrawal amount must be positive; "

             << "withdrawal canceled.\n";

    else if (amt <= Balance())

        AcctABC::Withdraw(amt);

    else

        cout << "Withdrawal amount of $" << amt

             << " exceeds your balance.\n"

             << "Withdrawal canceled.\n";

}

void Brass::ViewAcct() const

{

    Formatting f = SetFormat();

    cout << "Brass Client: " << FullName() << endl;

    cout << "Account Number: " << AcctNum() << endl;

    cout << "Balance: $" << Balance() << endl;

    Restore(f);

}

// BrassPlus Methods

BrassPlus::BrassPlus(const string & s, long an, double bal,

           double ml, double r) : AcctABC(s, an, bal)

{

    maxLoan = ml;

    owesBank = 0.0;

    rate = r;

}

BrassPlus::BrassPlus(const Brass & ba, double ml, double r)

           : AcctABC(ba)   // uses implicit copy constructor

{

    maxLoan = ml;

    owesBank = 0.0;

    rate = r;

}

void BrassPlus::ViewAcct() const

{

    Formatting f = SetFormat();

    cout << "BrassPlus Client: " << FullName() << endl;

    cout << "Account Number: " << AcctNum() << endl;

    cout << "Balance: $" << Balance() << endl;

    cout << "Maximum loan: $" << maxLoan << endl;

    cout << "Owed to bank: $" << owesBank << endl;

    cout.precision(3);

    cout << "Loan Rate: " << 100 * rate << "%\n";

    Restore(f);

}

void BrassPlus::Withdraw(double amt)

{

    Formatting f = SetFormat();

    double bal = Balance();

    if (amt <= bal)

        AcctABC::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);

        AcctABC::Withdraw(amt);

    }

    else

        cout << "Credit limit exceeded. Transaction cancelled.\n";

    Restore(f);

}

The FullName() and AcctNum() protected methods provide read-only access to the fullName and acctNum data members and make it possible to customize ViewAcct() a little more individually for each derived class.

This version makes a couple of improvements in the implementation of the formatting. The previous version used two function calls to set the formatting and one to restore it:

format initialState = setFormat();

precis prec = cout.precision(2);

...

restore(initialState, prec); // restore original format

The new version defines a structure to hold the two formatting values and uses that structure to set and restore formats with just two calls:

struct Formatting

{

     std::ios_base::fmtfglas flag;

     std::streamsize pr;

};

...

Formatting f = SetFormat();

...

Restore(f);

It’s a neater look.

A problem with the older version was that the original setFormat() and restore() were standalone functions, so those function names would conflict with client-defined functions of the same name. There are several ways to solve that problem. One is to declare both functions static, making them private to the brass.cpp file or to its successor, acctabc.cpp. A second is to place both functions and the struct Formatting definition into a namespace. But one of the topics for this example is protected access, so this example places the structure definition and the functions in the protected part of the class definition. This makes them available to the base class and the derived class while hiding them from the outside world.

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги