extending the class capabilities

of 36 /36
Savitch - Chapters 11&12 CS 150 1 Extending the Class Capabilities Let’s extend the definition of the BankAccount class to illustrate some additional capabilities provided by C++ classes. //////////////////////////////////////////////////////////////////////// // BankAcct.h // // The class definition for the "NEW AND IMPROVED" BankAccount class. // //////////////////////////////////////////////////////////////////////// #ifndef BANK_ACCOUNT_H using namespace std; const int ACCOUNT_NBR_LENGTH = 13; const int PIN_LENGTH = 7; class BankAccount { public: // Constructors BankAccount(); BankAccount(string newAccountNumber, string newPIN, float newBalance, float newInterestRate); BankAccount(const BankAccount &account); // Member Functions void setBalance(float newBalance); void setInterestRate(float newInterestRate); bool checkAccountNumber(string testAccountNumber); bool checkPIN(string testPIN); void deposit(float amount); void withdraw(float amount); const modifier

Author: ruby-yang

Post on 01-Jan-2016

29 views

Category:

Documents


0 download

Embed Size (px)

DESCRIPTION

Extending the Class Capabilities. Let’s extend the definition of the BankAccount class to illustrate some additional capabilities provided by C++ classes. //////////////////////////////////////////////////////////////////////// - PowerPoint PPT Presentation

TRANSCRIPT

  • Extending the Class CapabilitiesLets extend the definition of the BankAccount class to illustrate some additional capabilities provided by C++ classes.////////////////////////////////////////////////////////////////////////// BankAcct.h //// The class definition for the "NEW AND IMPROVED" BankAccount class. //////////////////////////////////////////////////////////////////////////#ifndef BANK_ACCOUNT_Husing namespace std;

    const int ACCOUNT_NBR_LENGTH = 13;const int PIN_LENGTH = 7;

    class BankAccount{ public: // Constructors BankAccount(); BankAccount(string newAccountNumber, string newPIN, float newBalance, float newInterestRate); BankAccount(const BankAccount &account);

    // Member Functions void setBalance(float newBalance); void setInterestRate(float newInterestRate); bool checkAccountNumber(string testAccountNumber); bool checkPIN(string testPIN); void deposit(float amount); void withdraw(float amount);const modifier

  • BankAcct.h (Continued) // Accessor Functions bool getActive() const; float getBalance() const; float getInterestRate() const; // Binary Operators bool operator == (const BankAccount &account) const; bool operator < (const BankAccount &account) const; bool operator (const BankAccount &account) const; bool operator >= (const BankAccount &account) const; bool operator != (const BankAccount &account) const;

    // Friend Functions friend void merge(BankAccount &accountA, BankAccount &accountB); friend istream& operator >> (istream &sourceFileStream, BankAccount &account); friend ostream& operator

  • BankAcct.h (Continued) private: // Member Functions void setActive(bool newActive); void setAccountNumber(string newAccountNumber); void setPIN(string newPIN);

    // Accessor Functions string getAccountNumber() const; string getPIN() const;

    // Data Members string accountNumber; bool active; string pin; float balance; float interestRate;};

    #define BANK_ACCOUNT_H#endifconst modifiersWell examine the const modifiers, overloaded operators, and friend functions as we come to them in the BankAccounts implementation file and in its driver program.

  • BankAcct.cpp//////////////////////////////////////////////////////////////////////////// BankAcct.cpp //// //// The class implementation for the NEW AND IMPROVED BankAccount class. ////////////////////////////////////////////////////////////////////////////#include #include #include #include "BankAcct.h"using namespace std;

    // Default constructor. Initializes no data members. //BankAccount::BankAccount(){}

    // Initializing constructor. Initializes appropriate data members //// to parameterized values; initializes active data member to true. //BankAccount::BankAccount(string newAccountNumber, string newPIN, float newBalance, float newInterestRate){ setAccountNumber(newAccountNumber); setPIN(newPIN); setBalance(newBalance); setInterestRate(newInterestRate); setActive(true);}

  • BankAcct.cpp (Continued)// Copy constructor. Duplicates the parameterized BankAccount. //BankAccount::BankAccount(const BankAccount &account){ string acctNbr; string pinNbr;

    account.getAccountNumber(acctNbr); setAccountNumber(acctNbr); setActive(account.getActive()); if (active) { account.getPIN(pinNbr); setPIN(pinNbr); setBalance(account.getBalance()); setInterestRate(account.getInterestRate()); } return;}const modifierNote that the parameter is sent by constant-reference, meaning that no duplicate is made, but that the member function must treat the parameter as a constant (i.e., it cannot alter any aspect of it).Since the member functions getAccountNumber, getActive, getPIN, getBalance, and getInterestRate are all applied to the account parameter, the compiler must be made aware that these member functions cannot alter the BankAccount to which they are applied.Well see how this is done when we get to theimplementations of those member functions.

  • BankAcct.cpp (Continued)// Member function to set the balance data member //// to the parameterized value (if appropriate). //void BankAccount::setBalance(float newBalance){ if (newBalance >= 0.0F) balance = newBalance; return;}

    // Member function to set the interestRate data member //// to the parameterized value (if appropriate). //void BankAccount::setInterestRate(float newInterestRate){ if (newInterestRate >= 0.0F) interestRate = newInterestRate; return;}

    // Member function to verify whether the accountNumber data //// member has the same value as the parameterized value. //bool BankAccount::checkAccountNumber(string testAccountNumber){ return (accountNumber == testAccountNumber)}

  • BankAcct.cpp (Continued)// Member function to verify whether the pin data member //// has the same value as the parameterized value. //bool BankAccount::checkPIN(string testPIN){ return (pin == testPIN)}

    // Member function to increment the balance data //// member by the parameterized value (if appropriate). //void BankAccount::deposit(float amount){ if (amount > 0.0F) balance += amount;}

    // Member function to decrement the balance data //// member by the parameterized value (if appropriate). //void BankAccount::withdraw(float amount){ if (amount

  • BankAcct.cpp (Continued)// Accessor member function for the active data member. //bool BankAccount::getActive() const{ return active;}

    // Accessor member function for the balance data member. //float BankAccount::getBalance() const{ return balance;}

    // Accessor member function for the interestRate data member. //float BankAccount::getInterestRate() const{ return interestRate;}By making these member functions constant, the compiler has been assured that they do not alter the associated BankAccount.If their code did try to alter the BankAccount, either directly or by invoking a non-constant member function, then the compilation would be halted and the code would have to be altered.const modifiers

  • BankAcct.cpp (Continued)// Equality operator. All inactive accounts are considered equal; //// active accounts with the same balance and interest rate are also //// considered equal; otherwise, accounts are not considered equal. //bool BankAccount::operator == (const BankAccount &account) const{ if ((!active) && (!account.active)) return true; else if ((!active) || (!account.active)) return false; else return ((interestRate == account.interestRate) && (balance == account.balance));}Several C++ operators (==, =, !=, =, +, -, *, /, %, ++, --, +=, -=, [], etc.) can be overloaded to apply to new classes.In this case, the equality operator has been overloaded for the BankAccount class, making it possible to test the equality of two BankAccount variables x and y with a simple statement like:if (x == y) ...Note that BankAccount equality has been defined very specifically.Also, notice that the parameter has been sent by constant-reference and that the operator has a const modifier, so neither BankAccount can be altered by the equality operator.overloaded operator

  • BankAcct.cpp (Continued)// Less-than operator. An inactive account is considered less than any //// active account; an active account is considered less than another //// active account if it has a smaller interest rate or, if they have //// the same interest rate and it has a smaller balance; otherwise, an //// account is not considered less than another account. //bool BankAccount::operator < (const BankAccount &account) const{ if (!account.active) return false; else if (!active) return true; else if (interestRate < account.interestRate) return true; else if (interestRate > account.interestRate) return false; else return (balance < account.balance);}

    // Less-than-or-equal operator. An account is considered //// less than or equal to another account if it is either //// less than (

  • BankAcct.cpp (Continued)// Greater-than operator. An account is considered greater than another //// account if the second account is less than ( (const BankAccount &account) const{ return (account < *this);}

    // Greater-than-or-equal operator. An account is considered //// greater than or equal to another account if the second //// account is less than or equal to (= (const BankAccount &account) const{ return ((*this > account) || (*this == account));}

    // Inequality operator. An account is considered unequal to another //// account if the account is not equal to (==) the other account. //bool BankAccount::operator != (const BankAccount &account) const{ return !(*this == account);}Again, each of these operators has been defined to take advantage of the previously defined operators.Also, observe that its okay to reverse the roles of *this and the parameter account in the > operators definition, since both BankAccount values have been subjected to a const modifier.overloaded operators

  • BankAcct.cpp (Continued)// Friend function to implement the input operator for BankAccounts. It is //// assumed that all BankAccount input will be formatted in the specified //// order: the accountNumber, followed by a character that indicates whether //// the BankAccount is active ('Y' means it is). If active, this character //// is followed by the PIN, the balance, and the interest rate. //istream& operator >> (istream &sourceFileStream, BankAccount &account){ string accountNbr; char activeIndicator; string pinNbr; float bal; float intRate;

    sourceFileStream >> accountNbr; account.setAccountNumber(accountNbr); sourceFileStream >> activeIndicator; if (activeIndicator != 'Y') account.setActive(false); else { account.setActive(true); sourceFileStream >> pinNbr; account.setPIN(pinNbr); sourceFileStream >> bal; account.setBalance(bal); sourceFileStream >> intRate; account.setInterestRate(intRate); } return sourceFileStream;}A friend function is not a member function of the class, but its friend designation does give it access to the private members of the class.While this tends to violate our information hiding principles, it does make it possible to implement fancy functions like this input operator, which can read a properly formatted BankAccount from an input stream.Note that friend functions may be implemented in either the class implementation or in the driver, but they must be declared as friends in the class definition itself. This affords the class at least a modicum of protection.friend function

  • BankAcct.cpp (Continued)// Friend function to implement the output operator for BankAccounts. Only //// the accountNumber and an inactive message is output for inactive accounts; //// an active account has its PIN, balance, and interestRate output as well. //ostream& operator
  • BankAcct.cpp (Continued)// Member function to set the active data member to the parameterized value. //void BankAccount::setActive(bool newActive){ active = newActive; return;}

    // Member function to set the accountNumber data member to the parameterized value. //void BankAccount::setAccountNumber(string newAccountNumber){ accountNumber = newAccountNumber; return;}

    // Member function to set the pin data member to the parameterized value. //void BankAccount::setPIN(string newPIN){ pin = newPIN; return;}

  • BankAcct.cpp (Continued)// Accessor member function for the accountNumber data member. //string BankAccount::getAccountNumber() const{return accountNumber;}

    // Accessor member function for the pin data member. //void BankAccount::getPIN() const{ return pin;}Finally, the last two accessor functions for the BankAccount class have const modifiers to assure the compiler that they dont alter the calling object, the BankAccount *this.const modifiersTo complete our introduction to these new features, well next examine a driver program to test the BankAccount class.

  • BankManagerDriver.cpp//////////////////////////////////////////////////////// BankManagerDriver.cpp //// //// This program permits a bank manager to retrieve, //// peruse, and alter a list of BankAccount data. ////////////////////////////////////////////////////////#include #include #include #include #include "BankAcct.h"using namespace std;

    const int MAX_ACCOUNT_CAPACITY = 16;

    void loadAccounts(BankAccount list[], int &length);char queryUser();void mergeTwoAccounts(BankAccount list[], int length);void openNewAccount(BankAccount list[], int &length);void updateAccount(BankAccount list[], int length);void viewAccount(BankAccount list[], int length);int indexOfAccount(string acctNbr, BankAccount list[], int length);Note that the prototype for the one remaining friend function of the BankAccount class, merge, is not included in the drivers list of prototypes, in spite of the fact that merge will actually be implemented in this driver.That is because that prototype has already been defined in BankAcct.h, the BankAccount class definition file.

  • BankManagerDriver.cpp (Continued)//////////////////////////////////////////////////////////////////////// The main function drives the bank manager's interactive session. ////////////////////////////////////////////////////////////////////////void main(){ BankAccount acctList[MAX_ACCOUNT_CAPACITY]; int listLength; char request;

    loadAccounts(acctList, listLength); request = queryUser(); while (request != 'Q') { switch (request) { case 'M': {mergeTwoAccounts(acctList, listLength); break;} case 'N': {openNewAccount(acctList, listLength); break;} case 'U': {updateAccount(acctList, listLength); break;} case 'V': {viewAccount(acctList, listLength); break;} } request = queryUser(); } return;}

  • BankManagerDriver.cpp (Continued)/////////////////////////////////////////////////////////////////////////////////// The merge function is a friend function to the BankAccount class. It //// combines the balances of two active BankAccounts into the BankAccount with //// the higher interest rate (or, if the interest rates are the same, the Bank- //// Account with the higher initial balance), and closes the other BankAccount. ///////////////////////////////////////////////////////////////////////////////////void merge(BankAccount &accountA, BankAccount &accountB){ if (accountA.accountNumber == accountB.accountNumber) return; if ((accountA.active) && (accountB.active)) { if (accountA >= accountB) { accountA.deposit(accountB.balance); accountB.setActive(false); } else { accountB.deposit(accountA.balance); accountA.setActive(false); } } return;}Here is the other friend function that was defined back in BankAcct.h.Note that, unlike regular functions defined in the driver, this function has access to every private member of the BankAccount class!friend function

  • BankManagerDriver.cpp (Continued)//////////////////////////////////////////////////////////////////////////////////// The loadAccounts function queries the user for the name of a file containing //// BankAccount information, opens that file, and extracts the BankAccount data, //// placing it into the parameterized array of BankAccounts. ////////////////////////////////////////////////////////////////////////////////////void loadAccounts(BankAccount list[], int &length){ ifstream bankFile; string bankFileName; cout > bankFileName; bankFile.open(bankFileName.c_str());

    bankFile >> length; for (int i = 0; i < length; i++) bankFile >> list[i];

    bankFile.close();}

  • BankManagerDriver.cpp (Continued)////////////////////////////////////////////////////////////////////////////// The queryUser function asks the user to input a letter indicating what //// BankAccount operation should be performed next. After the user enters //// a valid response, that letter is returned to the calling function. //////////////////////////////////////////////////////////////////////////////char queryUser(){ char ltr; cout
  • BankManagerDriver.cpp (Continued)///////////////////////////////////////////////////////////////////////////////////// The mergeTwoAccounts function queries the user for the account numbers of the //// two BankAccounts that are to be combined. If BankAccounts with these numbers //// reside in the parameterized list, then the accounts are appropriately merged. /////////////////////////////////////////////////////////////////////////////////////void mergeTwoAccounts(BankAccount list[], int length){ string acctNbr; BankAccount dummyAcct; int index[2];

    for (int i = 0; i

  • BankManagerDriver.cpp (Continued)/////////////////////////////////////////////////////////////////////////////////////// The openNewAccount function queries the user for the account number to be //// given to a brand new BankAccount. If that number doesn't already belong to //// one of the BankAccounts residing in the parameterized list, then a new //// BankAccount is created with the user-supplied account number, PIN, balance, //// and interest rate, and that BankAccount is added to the list (if there's room). ///////////////////////////////////////////////////////////////////////////////////////void openNewAccount(BankAccount list[], int &length){ string newAcctNbr; string newPIN; float newBal; float newIntRate; int index;

    if (length == MAX_ACCOUNT_CAPACITY) { cout

  • BankManagerDriver.cpp (Continued)cout > newPIN;cout > newBal;cout > newIntRate;BankAccount newAcct(newAcctNbr, newPIN, newBal, newIntRate);list[length] = newAcct;length++;cout
  • BankManagerDriver.cpp (Continued)//////////////////////////////////////////////////////////////////////////// The updateAccount function queries the user for the account number //// of a BankAccount whose balance is to be altered. If that number //// corresponds to one of the BankAccounts residing in the parameterized //// list, then the user is asked to supply the amount to be deposited or //// withdrawn from the account, and the transaction is properly handled. ////////////////////////////////////////////////////////////////////////////void updateAccount(BankAccount list[], int length){ string acctNbr; int index; char request; float amt;

    cout > acctNbr; index = indexOfAccount(acctNbr, list, length); if (index < 0) { cout

  • BankManagerDriver.cpp (Continued) cout > request; request = toupper(request); while ((request != 'D') && (request != 'W')) { cout > request; request = toupper(request); }

    cout > amt; if (request == 'D') list[index].deposit(amt); else list[index].withdraw(amt); cout

  • BankManagerDriver.cpp (Continued)////////////////////////////////////////////////////////////////////////////////////////// The viewAccount function queries the user for the account number of a BankAccount //// whose data is to be output. If that number corresponds to one of the BankAccounts //// residing in the parameterized list, then BankAccount is appropriately output. //////////////////////////////////////////////////////////////////////////////////////////void viewAccount(BankAccount list[], int length){ string acctNbr; int index;

    cout > acctNbr; index = indexOfAccount(acctNbr, list, length); if (index < 0) { cout

  • BankManagerDriver.cpp (Continued)/////////////////////////////////////////////////////////////////////////////////// The indexOfAccount function searches the parameterized list of BankAccounts //// for one with the parameterized account number. If one is found, its list //// index is returned; otherwise, a value of -1 is returned. ///////////////////////////////////////////////////////////////////////////////////int indexOfAccount(string acctNbr, BankAccount list[], int length){ for (int i = 0; i < length; i++) { if (list[i].checkAccountNumber(acctNbr)) return i; } return -1;}Now lets test the BankAccount class and this new driver.

  • Testing the View Function: Active & Inactive

  • Testing the View Function: Bad & Good Account Numbers

  • Testing the Merge Function

  • Testing the Update Function: Withdrawing Funds

  • Testing the Update Function: Withdrawing Too Much

  • Testing the Update Function: Depositing

  • Testing the Update Function: Depositing a Negative

  • Testing the New Account Function: An Unused Number

  • Testing the New Account Function: A Used Number