Class ATM (Figs. G.1G.2) represents the ATM as a whole. Figure G.1 contains the ATM class definition, enclosed in #ifndef, #define and #endif preprocessor directives to ensure that this definition only gets included once in a program. We discuss lines 611 shortly. Lines 1617 contain the function prototypes for the class's public member functions. The class diagram of Fig. 13.29 does not list any operations for class ATM, but we now declare a public member function run (line 17) in class ATM that allows an external client of the class (i.e., ATMCaseStudy.cpp) to tell the ATM to run. We also include a function prototype for a default constructor (line 16), which we discuss shortly.
Figure G.1. Definition of class ATM, which represents the ATM.
(This item is displayed on page 1286 in the print version)
1 // ATM.h 2 // ATM class definition. Represents an automated teller machine. 3 #ifndef ATM_H 4 #define ATM_H 5 6 #include "Screen.h" // Screen class definition 7 #include "Keypad.h" // Keypad class definition 8 #include "CashDispenser.h" // CashDispenser class definition 9 #include "DepositSlot.h" // DepositSlot class definition 10 #include "BankDatabase.h" // BankDatabase class definition 11 class Transaction; // forward declaration of class Transaction 12 13 class ATM 14 { 15 public: 16 ATM(); // constructor initializes data members 17 void run(); // start the ATM 18 private: 19 bool userAuthenticated; // whether user is authenticated 20 int currentAccountNumber; // current user's account number 21 Screen screen; // ATM's screen 22 Keypad keypad; // ATM's keypad 23 CashDispenser cashDispenser; // ATM's cash dispenser 24 DepositSlot depositSlot; // ATM's deposit slot 25 BankDatabase bankDatabase; // account information database 26 27 // private utility functions 28 void authenticateUser(); // attempts to authenticate user 29 void performTransactions(); // performs transactions 30 int displayMainMenu() const; // displays main menu 31 32 // return object of specified Transaction derived class 33 Transaction *createTransaction( int ); 34 }; // end class ATM 35 36 #endif // ATM_H |
Lines 1925 of Fig. G.1 implement the class's attributes as private data members. We determine all but one of these attributes from the UML class diagrams of Fig. 13.28 and Fig. 13.29. Note that we implement the UML Boolean attribute userAuthenticated in Fig. 13.29 as a bool data member in C++ (line 19). Line 20 declares a data member not found in our UML designan int data member currentAccountNumber that keeps track of the account number of the current authenticated user. We will soon see how the class uses this data member.
Lines 2124 create objects to represent the parts of the ATM. Recall from the class diagram of Fig. 13.28 that class ATM has composition relationships with classes Screen, Keypad, CashDispenser and DepositSlot, so class ATM is responsible for their creation. Line 25 creates a BankDatabase, with which the ATM interacts to access and manipulate bank account information. [Note: If this were a real ATM system, the ATM class would receive a reference to an existing database object created by the bank. However, in this implementation we are only simulating the bank's database, so class ATM creates the BankDatabase object with which it interacts.] Note that lines 610 #include the class definitions of Screen, Keypad, CashDispenser, DepositSlot and BankDatabase so that the ATM can store objects of these classes.
Lines 2830 and 33 contain function prototypes for private utility functions that the class uses to perform its tasks. We will see how these functions serve the class shortly. Note that member function createTransaction (line 33) returns a transaction pointer. To include the class name transaction in this file, we must at least include a forward declaration of class transaction (line 11). Recall that a forward declaration tells the compiler that a class exists, but that the class is defined elsewhere. A forward declaration is sufficient here, as we are using transaction only as a return typeif we were creating an actual TRansaction object, we would need to #include the full transaction header file.
ATM Class Member-Function Definitions
Figure G.2 contains the member-function definitions for class ATM. Lines 37 #include the header files required by the implementation file ATM.cpp. Note that including the ATM header file allows the compiler to ensure that the class's member functions are defined correctly. This also allows the member functions to use the class's data members.
Line 10 declares an enum named MenuOption that contains constants corresponding to the four options in the ATM's main menu (i.e., balance inquiry, withdrawal, deposit and exit). Note that setting BALANCE_INQUIRY to 1 causes the subsequent enumeration constants to be assigned the values 2, 3 and 4, as enumeration constant values increment by 1.
Figure G.2. ATM class member-function definitions.
(This item is displayed on pages 1287 - 1290 in the print version)
1 // ATM.cpp 2 // Member-function definitions for class ATM. 3 #include "ATM.h" // ATM class definition 4 #include "Transaction.h" // Transaction class definition 5 #include "BalanceInquiry.h" // BalanceInquiry class definition 6 #include "Withdrawal.h" // Withdrawal class definition 7 #include "Deposit.h" // Deposit class definition 8 9 // enumeration constants represent main menu options 10 enum MenuOption { BALANCE_INQUIRY = 1, WITHDRAWAL, DEPOSIT, EXIT }; 11 12 // ATM default constructor initializes data members 13 ATM::ATM() 14 : userAuthenticated ( false ), // user is not authenticated to start 15 currentAccountNumber( 0 ) // no current account number to start 16 { 17 // empty body 18 } // end ATM default constructor 19 20 // start ATM 21 void ATM::run() 22 { 23 // welcome and authenticate user; perform transactions 24 while ( true ) 25 { 26 // loop while user is not yet authenticated 27 while ( !userAuthenticated ) 28 { 29 screen.displayMessageLine( " Welcome!" ); 30 authenticateUser(); // authenticate user 31 } // end while 32 33 performTransactions(); // user is now authenticated 34 userAuthenticated = false; // reset before next ATM session 35 currentAccountNumber = 0; // reset before next ATM session 36 screen.displayMessageLine( " Thank you! Goodbye!" ); 37 } // end while 38 } // end function run 39 40 // attempt to authenticate user against database 41 void ATM::authenticateUser() 42 { 43 screen.displayMessage( " Please enter your account number: " ); 44 int accountNumber = keypad.getInput(); // input account number 45 screen.displayMessage( " Enter your PIN: " ); // prompt for PIN 46 int pin = keypad.getInput(); // input PIN 47 48 // set userAuthenticated to bool value returned by database 49 userAuthenticated = 50 bankDatabase.authenticateUser( accountNumber, pin ); 51 52 // check whether authentication succeeded 53 if ( userAuthenticated ) 54 { 55 currentAccountNumber = accountNumber; // save user's account # 56 } // end if 57 else 58 screen.displayMessageLine( 59 "Invalid account number or PIN. Please try again." ); 60 } // end function authenticateUser 61 62 // display the main menu and perform transactions 63 void ATM::performTransactions() 64 { 65 // local pointer to store transaction currently being processed 66 Transaction *currentTransactionPtr; 67 68 bool userExited = false; // user has not chosen to exit 69 70 // loop while user has not chosen option to exit system 71 while ( !userExited ) 72 { 73 // show main menu and get user selection 74 int mainMenuSelection = displayMainMenu(); 75 76 // decide how to proceed based on user's menu selection 77 switch ( mainMenuSelection ) 78 { 79 // user chose to perform one of three transaction types 80 case BALANCE_INQUIRY: 81 case WITHDRAWAL: 82 case DEPOSIT: 83 // initialize as new object of chosen type 84 currentTransactionPtr = 85 createTransaction( mainMenuSelection ); 86 87 currentTransactionPtr->execute(); // execute transaction 88 89 // free the space for the dynamically allocated Transaction 90 delete currentTransactionPtr; 91 92 break; 93 case EXIT: // user chose to terminate session 94 screen.displayMessageLine( " Exiting the system..." ); 95 userExited = true; // this ATM session should end 96 break; 97 default: // user did not enter an integer from 1-4 98 screen.displayMessageLine( 99 " You did not enter a valid selection. Try again." ); 100 break; 101 } // end switch 102 } // end while 103 } // end function performTransactions 104 105 // display the main menu and return an input selection 106 int ATM::displayMainMenu() const 107 { 108 screen.displayMessageLine( " Main menu:" ); 109 screen.displayMessageLine( "1 - View my balance" ); 110 screen.displayMessageLine( "2 - Withdraw cash" ); 111 screen.displayMessageLine( "3 - Deposit funds" ); 112 screen.displayMessageLine( "4 - Exit " ); 113 screen.displayMessage( "Enter a choice: " ); 114 return keypad.getInput(); // return user's selection 115 } // end function displayMainMenu 116 117 // return object of specified Transaction derived class 118 Transaction *ATM::createTransaction( int type ) 119 { 120 Transaction *tempPtr; // temporary Transaction pointer 121 122 // determine which type of Transaction to create 123 switch ( type ) 124 { 125 case BALANCE_INQUIRY: // create new BalanceInquiry transaction 126 tempPtr = new BalanceInquiry( 127 currentAccountNumber, screen, bankDatabase ); 128 break; 129 case WITHDRAWAL: // create new Withdrawal transaction 130 tempPtr = new Withdrawal( currentAccountNumber, screen, 131 bankDatabase, keypad, cashDispenser ); 132 break; 133 case DEPOSIT: // create new Deposit transaction 134 tempPtr = new Deposit( currentAccountNumber, screen, 135 bankDatabase, keypad, depositSlot ); 136 break; 137 } // end switch 138 139 return tempPtr; // return the newly created object 140 } // end function createTransaction |
Lines 1318 define class ATM's constructor, which initializes the class's data members. When an ATM object is first created, no user is authenticated, so line 14 uses a member initializer to set userAuthenticated to false. Likewise, line 15 initializes currentAccountNumber to 0 because there is no current user yet.
ATM member function run (lines 2138) uses an infinite loop (lines 2437) to repeatedly welcome a user, attempt to authenticate the user and, if authentication succeeds, allow the user to perform transactions. After an authenticated user performs the desired transactions and chooses to exit, the ATM resets itself, displays a goodbye message to the user and restarts the process. We use an infinite loop here to simulate the fact that an ATM appears to run continuously until the bank turns it off (an action beyond the user's control). An ATM user has the option to exit the system, but does not have the ability to turn off the ATM completely.
Inside member function run's infinite loop, lines 2731 cause the ATM to repeatedly welcome and attempt to authenticate the user as long as the user has not been authenticated (i.e., !userAuthenticated is true). Line 29 invokes member function displayMessageLine of the ATM's screen to display a welcome message. Like Screen member function displayMessage designed in the case study, member function displayMessageLine (declared in line 13 of Fig. G.3 and defined in lines 2023 of Fig. G.4) displays a message to the user, but this member function also outputs a newline after displaying the message. We have added this member function during implementation to give class Screen's clients more control over the placement of displayed messages. Line 30 of Fig. G.2 invokes class ATM's private utility function authenticateUser (lines 4160) to attempt to authenticate the user.
We refer to the requirements document to determine the steps necessary to authenticate the user before allowing transactions to occur. Line 43 of member function authenticateUser invokes member function displayMessage of the ATM's screen to prompt the user to enter an account number. Line 44 invokes member function getInput of the ATM's keypad to obtain the user's input, then stores the integer value entered by the user in a local variable accountNumber. Member function authenticateUser next prompts the user to enter a PIN (line 45), and stores the PIN input by the user in a local variable pin (line 46). Next, lines 4950 attempt to authenticate the user by passing the accountNumber and pin entered by the user to the bankDatabase's authenticateUser member function. Class ATM sets its userAuthenticated data member to the bool value returned by this functionuserAuthenticated becomes true if authentication succeeds (i.e., accountNumber and pin match those of an existing Account in bankDatabase) and remains false otherwise. If userAuthenticated is true, line 55 saves the account number entered by the user (i.e., accountNumber) in the ATM data member currentAccountNumber. The other member functions of class ATM use this variable whenever an ATM session requires access to the user's account number. If userAuthenticated is false, lines 5859 use the screen's displayMessageLine member function to indicate that an invalid account number and/or PIN was entered and the user must try again. Note that we set currentAccountNumber only after authenticating the user's account number and the associated PINif the database could not authenticate the user, currentAccountNumber remains 0.
After member function run attempts to authenticate the user (line 30), if userAuthenticated is still false, the while loop in lines 2731 executes again. If userAuthenticated is now TRue, the loop terminates and control continues with line 33, which calls class ATM's utility function performTransactions.
Member function performTransactions (lines 63103) carries out an ATM session for an authenticated user. Line 66 declares a local TRansaction pointer, which we aim at a BalanceInquiry, Withdrawal or Deposit object representing the ATM transaction currently being processed. Note that we use a TRansaction pointer here to allow us to take advantage of polymorphism. Also note that we use the role name included in the class diagram of Fig. 3.20currentTransactionin naming this pointer. As per our pointer-naming convention, we append "Ptr" to the role name to form the variable name currentTransactionPtr. Line 68 declares another local variablea bool called userExited that keeps track of whether the user has chosen to exit. This variable controls a while loop (lines 71102) that allows the user to execute an unlimited number of transactions before choosing to exit. Within this loop, line 74 displays the main menu and obtains the user's menu selection by calling an ATM utility function displayMainMenu (defined in lines 106115). This member function displays the main menu by invoking member functions of the ATM's screen and returns a menu selection obtained from the user through the ATM's keypad. Note that this member function is const because it does not modify the contents of the object. Line 74 stores the user's selection returned by displayMainMenu in local variable mainMenuSelection.
After obtaining a main menu selection, member function performTransactions uses a switch statement (lines 77101) to respond to the selection appropriately. If main-MenuSelection is equal to any of the three enumeration constants representing transaction types (i.e., if the user chose to perform a transaction), lines 8485 call utility function createTransaction (defined in lines 118140) to return a pointer to a newly instantiated object of the type that corresponds to the selected transaction. Pointer currentTransactionPtr is assigned the pointer returned by createTransaction. Line 87 then uses currentTransactionPtr to invoke the new object's execute member function to execute the transaction. We will discuss TRansaction member function execute and the three TRansaction derived classes shortly. Finally, when the transaction derived class object is no longer needed, line 90 releases the memory dynamically allocated for it.
Note that we aim the transaction pointer currentTransactionPtr at an object of one of the three TRansaction derived classes so that we can execute transactions polymorphically. For example, if the user chooses to perform a balance inquiry, mainMenuSelection equals BALANCE_INQUIRY, leading createTransaction to return a pointer to a BalanceInquiry object. Thus, currentTransactionPtr points to a BalanceInquiry, and invoking currentTransactionPtr->execute() results in BalanceInquiry's version of execute being called.
Member function createTransaction (lines 118140) uses a switch statement (lines 123137) to instantiate a new transaction derived class object of the type indicated by the parameter type. Recall that member function performTransactions passes mainMenuSelection to this member function only when mainMenuSelection contains a value corresponding to one of the three transaction types. Therefore type equals either BALANCE_INQUIRY, WITHDRAWAL or DEPOSIT. Each case in the switch statement aims the temporary pointer tempPtr at a newly created object of the appropriate TRansaction derived class. Note that each constructor has a unique parameter list, based on the specific data required to initialize the derived class object. A BalanceInquiry requires only the account number of the current user and references to the ATM's screen and the bankDatabase. In addition to these parameters, a Withdrawal requires references to the ATM's keypad and cashDispenser, and a Deposit requires references to the ATM's keypad and depositSlot. Note that, as you will soon see, the BalanceInquiry, Withdrawal and Deposit constructors each specify reference parameters to receive the objects representing the required parts of the ATM. Thus, when member function createTransaction passes objects in the ATM (e.g., screen and keypad) to the initializer for each newly created TRansaction derived class object, the new object actually receives references to the ATM's composite objects. We discuss the transaction classes in more detail in Section G.9Section G.12.
After executing a transaction (line 87 in performTransactions), userExited remains false and the while loop in lines 71102 repeats, returning the user to the main menu. However, if a user does not perform a transaction and instead selects the main menu option to exit, line 95 sets userExited to TRue, causing the condition of the while loop (!userExited) to become false. This while is the final statement of member function performTransactions, so control returns to the calling function run. If the user enters an invalid main menu selection (i.e., not an integer from 14), lines 9899 display an appropriate error message, userExited remains false and the user returns to the main menu to try again.
When performTransactions returns control to member function run, the user has chosen to exit the system, so lines 3435 reset the ATM's data members userAuthenticated and currentAccountNumber to prepare for the next ATM user. Line 36 displays a goodbye message before the ATM starts over and welcomes the next user.
Introduction to Computers, the Internet and World Wide Web
Introduction to C++ Programming
Introduction to Classes and Objects
Control Statements: Part 1
Control Statements: Part 2
Functions and an Introduction to Recursion
Arrays and Vectors
Pointers and Pointer-Based Strings
Classes: A Deeper Look, Part 1
Classes: A Deeper Look, Part 2
Operator Overloading; String and Array Objects
Object-Oriented Programming: Inheritance
Object-Oriented Programming: Polymorphism
Templates
Stream Input/Output
Exception Handling
File Processing
Class string and String Stream Processing
Web Programming
Searching and Sorting
Data Structures
Bits, Characters, C-Strings and structs
Standard Template Library (STL)
Other Topics
Appendix A. Operator Precedence and Associativity Chart
Appendix B. ASCII Character Set
Appendix C. Fundamental Types
Appendix D. Number Systems
Appendix E. C Legacy Code Topics
Appendix F. Preprocessor
Appendix G. ATM Case Study Code
Appendix H. UML 2: Additional Diagram Types
Appendix I. C++ Internet and Web Resources
Appendix J. Introduction to XHTML
Appendix K. XHTML Special Characters
Appendix L. Using the Visual Studio .NET Debugger
Appendix M. Using the GNU C++ Debugger
Bibliography