Class ATM
(Figs. 23.14–23.15) represents the ATM as a whole. Figure 23.14 contains the ATM
class definition, enclosed in #ifndef
, #define
and #endif
preprocessor directives to ensure that this definition gets included only once in a program. We discuss lines 6–11 shortly. Lines 16–17 contain the function prototypes for the class’s public
member functions. The class diagram of Fig. 23.11 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.
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 19–25 of Fig. 23.14 implement the class’s attributes as private
data members. We determine all but one of these attributes from the class diagrams of Figs. 23.10–23.11. We implement the UML Boolean
attribute userAuthenticated
in Fig. 23.11 as a bool
data member in C++ (line 19). Line 20 declares a data member not found in our UML design—an int
data member currentAccountNumber
that keeps track of the account number of the current authenticated user. We’ll soon see how the class uses this data member.
Lines 21–24 create objects to represent the parts of the ATM. Recall from the class diagram of Fig. 23.10 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.] Lines 6–10 #include
the class definitions of Screen
, Keypad
, CashDispenser
, DepositSlot
and BankDatabase
so that the ATM
can store objects of these classes.
Lines 28–30 and 33 contain function prototypes for private
utility functions that the class uses to perform its tasks. We’ll see how these functions serve the class shortly. 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 a Transaction
pointer as a return type—if we were creating or returning an actual Transaction
object, we would need to #include
the full Transaction
header file.
Figure 23.15 contains the member-function definitions for class ATM
. Lines 3–7 #include
the header files required by the implementation file ATM.cpp
. 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.
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
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
.
Lines 13–18 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 21–38) uses an infinite loop (lines 24–37) 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 27–31 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. 23.16 and defined in lines 20–23 of Fig. 23.17) displays a message to the user, but this member function also outputs a newline after displaying the message. We’ve added this member function during implementation to give class Screen
’s clients more control over the placement of displayed messages. Line 30 of Fig. 23.15 invokes class ATM
’s private
utility function authenticateUser
(lines 41–60) to attempt to authenticate the user.
1 // Screen.h
2 // Screen class definition. Represents the screen of the ATM.
3 #ifndef SCREEN_H
4 #define SCREEN_H
5
6 #include <string>
7 using namespace std;
8
9 class Screen
10 {
11 public:
12 void displayMessage( string ) const; // output a message
13 void displayMessageLine( string ) const; // output message with newline
14 void displayDollarAmount( double ) const; // output a dollar amount
15 }; // end class Screen
16
17 #endif // SCREEN_H
1 // Screen.cpp
2 // Member-function definitions for class Screen.
3 #include <iostream>
4 #include <iomanip>
5 #include "Screen.h" // Screen class definition
6 using namespace std;
7
8 // output a message without a newline
9 void Screen::displayMessage( string message ) const
10 {
11 cout << message;
12 } // end function displayMessage
13
14 // output a message with a newline
15 void Screen::displayMessageLine( string message ) const
16 {
17 cout << message << endl;
18 } // end function displayMessageLine
19
20 // output a dollar amount
21 void Screen::displayDollarAmount( double amount ) const
22 {
23 cout << fixed << setprecision( 2 ) << "$" << amount;
24 } // end function displayDollarAmount
We refer to the requirements specification 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 49–50 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 function—userAuthenticated
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 58–59 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 PIN—if 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 27–31 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 63–103) 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. We use a Transaction
pointer here to allow us to take advantage of polymorphism. Also, we use the role name included in the class diagram of Fig. 22.7—currentTransaction
—in 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 variable—a bool
called userExited
that keeps track of whether the user has chosen to exit. This variable controls a while
loop (lines 71–102) 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 106–115). 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 77–101) to respond to the selection appropriately. If mainMenuSelection
is equal to any of the three enumeration constants representing transaction types (i.e., if the user chose to perform a transaction), lines 84–85 call utility function createTransaction
(defined in lines 118–140) 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’ll 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.
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 118–140) uses a switch
statement (lines 123–137) 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. 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
. As you’ll 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 Sections 23.4.8––23.4.11.
After executing a transaction (line 87 in performTransactions
), userExited
remains false
and the while
loop in lines 71–102 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 1–4), lines 98–99 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 34–35 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.
18.117.91.2