www.gibmonks.com

Main Page

Previous Page
Next Page

[Page 1286 (continued)]

G.2. Class ATM

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.


[Page 1287]
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.


[Page 1290]
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( "\nWelcome!" );
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( "\nThank 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( "\nPlease enter your account number: " );
44     int accountNumber = keypad.getInput(); // input account number
45     screen.displayMessage( "\nEnter 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( "\nExiting 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                 "\nYou 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( "\nMain 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\n" );
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.


[Page 1291]

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.


[Page 1292]

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.


Previous Page
Next Page