Presentation is loading. Please wait.

Presentation is loading. Please wait.

Savitch - Chapter 11CS 15097 Extending the Class Capabilities Let’s extend the definition of the BankAccount class to illustrate some additional capabilities.

Similar presentations


Presentation on theme: "Savitch - Chapter 11CS 15097 Extending the Class Capabilities Let’s extend the definition of the BankAccount class to illustrate some additional capabilities."— Presentation transcript:

1 Savitch - Chapter 11CS 15097 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

2 Savitch - Chapter 11CS 15098 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; 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 << (ostream &destinationFileStream, const BankAccount &account); const modifiers overloaded operators friend functions

3 Savitch - Chapter 11CS 15099 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 #endif const modifiers We’ll examine the const modifiers, overloaded operators, and friend functions as we come to them in the BankAccount’s implementation file and in its driver program.

4 Savitch - Chapter 11CS 150100 BankAcct.cpp ////////////////////////////////////////////////////////////////////////// // BankAcct.cpp // // // The class implementation for the NEW AND IMPROVED BankAccount class. // ////////////////////////////////////////////////////////////////////////// #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); }

5 Savitch - Chapter 11CS 150101 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 modifier Note 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. We’ll see how this is done when we get to the implementations of those member functions.

6 Savitch - Chapter 11CS 150102 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) }

7 Savitch - Chapter 11CS 150103 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 <= balance) balance -= amount; return; }

8 Savitch - Chapter 11CS 150104 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

9 Savitch - Chapter 11CS 150105 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

10 Savitch - Chapter 11CS 150106 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 (<) or equal to (==) the other account. // bool BankAccount::operator <= (const BankAccount &account) const { return ((*this < account) || (*this == account)); } Notice that the <= operator has been defined to take advantage of the previously defined < and == operators. Also, observe the use of *this when referring to the “calling object”, in this case, the first BankAccount in the comparison. overloaded operators

11 Savitch - Chapter 11CS 150107 BankAcct.cpp (Continued) // Greater-than operator. An account is considered greater than another // // account if the second account is less than (<) the first account. // bool BankAccount::operator > (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 (<=) the first account. // bool BankAccount::operator >= (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 it’s okay to reverse the roles of *this and the parameter account in the > operator’s definition, since both BankAccount values have been subjected to a const modifier. overloaded operators

12 Savitch - Chapter 11CS 150108 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

13 Savitch - Chapter 11CS 150109 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 << (ostream &destinationFileStream, const BankAccount &account) { destinationFileStream.setf(ios::fixed); destinationFileStream << setprecision(2); string accountNbr; account.getAccountNumber(accountNbr); destinationFileStream << "Account Number: " << accountNbr << endl; if (account.getActive() == false) destinationFileStream << "**** ACCOUNT INACTIVE ****"; else { string pinNbr; account.getPIN(pinNbr); destinationFileStream << "PIN: " << pinNbr << endl; destinationFileStream << "Interest Rate: " << 100*account.getInterestRate() << '%' << endl; destinationFileStream << "Current Balance: $" << account.getBalance(); } return destinationFileStream; } This friend function implements the output operator for the BankAccount class. Notice how dangerous this is: while the accessor functions for the accountNumber and pin data members were private, this operator is public, permitting any driver to output that information! It would probably be smarter to implement this friend function in a driver where this kind of output operator would be appropriate. friend function

14 Savitch - Chapter 11CS 150110 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; }

15 Savitch - Chapter 11CS 150111 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 don’t alter the “calling object”, the BankAccount *this. const modifiers To complete our introduction to these new features, we’ll next examine a driver program to test the BankAccount class.

16 Savitch - Chapter 11CS 150112 BankManagerDriver.cpp ////////////////////////////////////////////////////// // BankManagerDriver.cpp // // // This program permits a bank manager to retrieve, // // peruse, and alter a list of BankAccount data. // ////////////////////////////////////////////////////// #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 driver’s 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.

17 Savitch - Chapter 11CS 150113 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; }

18 Savitch - Chapter 11CS 150114 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

19 Savitch - Chapter 11CS 150115 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 << "Enter the name of the file containing the bank account data: "; cin >> bankFileName; bankFile.open(bankFileName.c_str()); bankFile >> length; for (int i = 0; i < length; i++) bankFile >> list[i]; bankFile.close(); }

20 Savitch - Chapter 11CS 150116 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 << "Select the letter corresponding to the function you wish to perform:” << endl << endl; cout << '\t' << "U - Update an existing account" << endl << '\t' << "V - View an existing account" << endl << '\t' << "N - Open a new account" << endl << '\t' << "M - Merge two existing accounts" << endl << '\t' << "Q - Quit processing bank accounts" << endl << endl << "SELECT ONE LETTER NOW: "; cin >> ltr; ltr = toupper(ltr); while ((ltr != 'U') && (ltr != 'V') && (ltr != 'N') && (ltr != 'M') && (ltr != 'Q')) { cout << "You must choose one of the letters listed above. Try again: "; cin >> ltr; ltr = toupper(ltr); } return ltr; }

21 Savitch - Chapter 11CS 150117 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 <= 1; i++) { if (i == 0) cout << "Enter the account number of the first account: "; else cout << "Enter the account number of the second account: "; cin >> acctNbr; index[i] = indexOfAccount(acctNbr, list, length); if (index[i] < 0) { cout << "NO ACCOUNT WITH THAT NUMBER. REQUEST DENIED." << endl << endl; return; } merge(list[index[0]], list[index[1]]); cout << "ACCOUNT MERGER PROCESSED." << endl << endl; return; }

22 Savitch - Chapter 11CS 150118 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 << "NO ROOM FOR MORE ACCOUNTS. REQUEST DENIED." << endl << endl; return; } cout << "Enter the account number for the new account: "; cin >> newAcctNbr; index = indexOfAccount(newAcctNbr, list, length); if (index >= 0) { cout << "DUPLICATE ACCOUNT NUMBER. REQUEST DENIED." << endl << endl; return; }

23 Savitch - Chapter 11CS 150119 BankManagerDriver.cpp (Continued) cout << "Enter the PIN for the new account: "; cin >> newPIN; cout << "Enter the initial balance for the new account: $"; cin >> newBal; cout << "Enter the interest rate for the new account: "; cin >> newIntRate; BankAccount newAcct(newAcctNbr, newPIN, newBal, newIntRate); list[length] = newAcct; length++; cout << "NEW ACCOUNT PROCESSED." << endl << endl; return; }

24 Savitch - Chapter 11CS 150120 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 << "Enter the account number of the account being updated: "; cin >> acctNbr; index = indexOfAccount(acctNbr, list, length); if (index < 0) { cout << "NO ACCOUNT WITH THAT NUMBER. REQUEST DENIED." << endl << endl; return; }

25 Savitch - Chapter 11CS 150121 BankManagerDriver.cpp (Continued) cout << "Enter \"D\" for deposit or \"W\" for withdrawal: "; cin >> request; request = toupper(request); while ((request != 'D') && (request != 'W')) { cout << "You must enter \"D\" or \"W\". Please try again: "; cin >> request; request = toupper(request); } cout << "Enter the amount: $"; cin >> amt; if (request == 'D') list[index].deposit(amt); else list[index].withdraw(amt); cout << "ACCOUNT UPDATE PROCESSED." << endl << endl; return; }

26 Savitch - Chapter 11CS 150122 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 << "Enter the account number of the account to be displayed: "; cin >> acctNbr; index = indexOfAccount(acctNbr, list, length); if (index < 0) { cout << "NO ACCOUNT WITH THAT NUMBER. REQUEST DENIED." << endl << endl; return; } cout << list[index] << endl << endl; return; }

27 Savitch - Chapter 11CS 150123 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 let’s test the BankAccount class and this new driver.

28 Savitch - Chapter 11CS 150124 Testing the View Function: Active & Inactive

29 Savitch - Chapter 11CS 150125 Testing the View Function: Bad & Good Account Numbers

30 Savitch - Chapter 11CS 150126 Testing the Merge Function

31 Savitch - Chapter 11CS 150127 Testing the Update Function: Withdrawing Funds

32 Savitch - Chapter 11CS 150128 Testing the Update Function: Withdrawing Too Much

33 Savitch - Chapter 11CS 150129 Testing the Update Function: Depositing

34 Savitch - Chapter 11CS 150130 Testing the Update Function: Depositing a Negative

35 Savitch - Chapter 11CS 150131 Testing the New Account Function: An Unused Number

36 Savitch - Chapter 11CS 150132 Testing the New Account Function: A Used Number


Download ppt "Savitch - Chapter 11CS 15097 Extending the Class Capabilities Let’s extend the definition of the BankAccount class to illustrate some additional capabilities."

Similar presentations


Ads by Google