In the "Software Engineering Case Study" sections in Chapters 17, we introduced the fundamentals of object orientation and developed an object-oriented design for our ATM system. Earlier in this chapter, we discussed many of the details of programming with C++ classes. We now begin implementing our object-oriented design in C++. At the end of this section, we show how to convert class diagrams to C++ header files. In the final "Software Engineering Case Study" section (Section 13.10), we modify the header files to incorporate the object-oriented concept of inheritance. We present the full C++ code implementation in Appendix G.
Visibility
We now apply access specifiers to the members of our classes. In Chapter 3, we introduced access specifiers public and private. Access specifiers determine the visibility or accessibility of an object's attributes and operations to other objects. Before we can begin implementing our design, we must consider which attributes and operations of our classes should be public and which should be private.
In Chapter 3, we observed that data members normally should be private and that member functions invoked by clients of a given class should be public. Member functions that are called only by other member functions of the class as "utility functions," however, normally should be private. The UML employs visibility markers for modeling the visibility of attributes and operations. Public visibility is indicated by placing a plus sign (+) before an operation or an attribute; a minus sign () indicates private visibility. Figure 9.20 shows our updated class diagram with visibility markers included. [Note: We do not include any operation parameters in Fig. 9.20. This is perfectly normal. Adding visibility markers does not affect the parameters already modeled in the class diagrams of Figs. 6.226.25.]
Figure 9.20. Class diagram with visibility markers.
(This item is displayed on page 510 in the print version)
Navigability
Before we begin implementing our design in C++, we introduce an additional UML notation. The class diagram in Fig. 9.21 further refines the relationships among classes in the ATM system by adding navigability arrows to the association lines. Navigability arrows (represented as arrows with stick arrowheads in the class diagram) indicate in which direction an association can be traversed and are based on the collaborations modeled in communication and sequence diagrams (see Section 7.12). When implementing a system designed using the UML, programmers use navigability arrows to help determine which objects need references or pointers to other objects. For example, the navigability arrow pointing from class ATM to class BankDatabase indicates that we can navigate from the former to the latter, thereby enabling the ATM to invoke the BankDatabase's operations. However, since Fig. 9.21 does not contain a navigability arrow pointing from class BankDatabase to class ATM, the BankDatabase cannot access the ATM's operations. Note that associations in a class diagram that have navigability arrows at both ends or do not have navigability arrows at all indicate bidirectional navigabilitynavigation can proceed in either direction across the association.
Figure 9.21. Class diagram with navigability arrows.
(This item is displayed on page 511 in the print version)
Like the class diagram of Fig. 3.23 the class diagram of Fig. 9.21 omits classes BalanceInquiry and Deposit to keep the diagram simple. The navigability of the associations in which these classes participate closely parallels the navigability of class Withdrawal's associations. Recall from Section 3.11 that BalanceInquiry has an association with class Screen. We can navigate from class BalanceInquiry to class Screen along this association, but we cannot navigate from class Screen to class BalanceInquiry. Thus, if we were to model class BalanceInquiry in Fig. 9.21, we would place a navigability arrow at class Screen's end of this association. Also recall that class Deposit associates with classes Screen, Keypad and DepositSlot. We can navigate from class Deposit to each of these classes, but not vice versa. We therefore would place navigability arrows at the Screen, Keypad and DepositSlot ends of these associations. [Note: We model these additional classes and associations in our final class diagram in Section 13.10, after we have simplified the structure of our system by incorporating the object-oriented concept of inheritance.]
Implementing the ATM System from Its UML Design
We are now ready to begin implementing the ATM system. We first convert the classes in the diagrams of Fig. 9.20 and Fig. 9.21 into C++ header files. This code will represent the "skeleton" of the system. In Chapter 13, we modify the header files to incorporate the object-oriented concept of inheritance. In Appendix G, ATM Case Study Code, we present the complete working C++ code for our model.
As an example, we begin to develop the header file for class Withdrawal from our design of class Withdrawal in Fig. 9.20. We use this figure to determine the attributes and operations of the class. We use the UML model in Fig. 9.21 to determine the associations among classes. We follow the following five guidelines for each class:
Figure 9.22. Definition of class Withdrawal enclosed in preprocessor wrappers.
(This item is displayed on page 512 in the print version)
1 // Fig. 9.22: Withdrawal.h 2 // Definition of class Withdrawal that represents a withdrawal transaction 3 #ifndef WITHDRAWAL_H 4 #define WITHDRAWAL_H 5 6 class Withdrawal 7 { 8 }; // end class Withdrawal 9 10 #endif // WITHDRAWAL_H |
Figure 9.23. Adding attributes to the Withdrawal class header file.
(This item is displayed on page 513 in the print version)
1 // Fig. 9.23: Withdrawal.h 2 // Definition of class Withdrawal that represents a withdrawal transaction 3 #ifndef WITHDRAWAL_H 4 #define WITHDRAWAL_H 5 6 class Withdrawal 7 { 8 private: 9 // attributes 10 int accountNumber; // account to withdraw funds from 11 double amount; // amount to withdraw 12 }; // end class Withdrawal 13 14 #endif // WITHDRAWAL_H |
Figure 9.24. Declaring references to objects associated with class Withdrawal.
(This item is displayed on page 513 in the print version)
1 // Fig. 9.24: Withdrawal.h 2 // Definition of class Withdrawal that represents a withdrawal transaction 3 #ifndef WITHDRAWAL_H 4 #define WITHDRAWAL_H 5 6 #include "Screen.h" // include definition of class Screen 7 #include "Keypad.h" // include definition of class Keypad 8 #include "CashDispenser.h" // include definition of class CashDispenser 9 #include "BankDatabase.h" // include definition of class BankDatabase 10 11 class Withdrawal 12 { 13 private: 14 // attributes 15 int accountNumber; // account to withdraw funds from 16 double amount; // amount to withdraw 17 18 // references to associated objects 19 Screen &screen; // reference to ATM's screen 20 Keypad &keypad; // reference to ATM's keypad 21 CashDispenser &cashDispenser; // reference to ATM's cash dispenser 22 BankDatabase &bankDatabase; // reference to the account info database 23 }; // end class Withdrawal 24 25 #endif // WITHDRAWAL_H |
Figure 9.25. Using forward declarations in place of #include directives.
(This item is displayed on page 514 in the print version)
1 // Fig. 9.25: Withdrawal.h 2 // Definition of class Withdrawal that represents a withdrawal transaction 3 #ifndef WITHDRAWAL_H 4 #define WITHDRAWAL_H 5 6 class Screen; // forward declaration of class Screen 7 class Keypad; // forward declaration of class Keypad 8 class CashDispenser; // forward declaration of class CashDispenser 9 class BankDatabase; // forward declaration of class BankDatabase 10 11 class Withdrawal 12 { 13 private: 14 // attributes 15 int accountNumber; // account to withdraw funds from 16 double amount; // amount to withdraw 17 18 // references to associated objects 19 Screen &screen; // reference to ATM's screen 20 Keypad &keypad; // reference to ATM's keypad 21 CashDispenser &cashDispenser; // reference to ATM's cash dispenser 22 BankDatabase &bankDatabase; // reference to the account info database 23 }; // end class Withdrawal 24 25 #endif // WITHDRAWAL_H |
Note that using a forward declaration (where possible) instead of including a full header file helps avoid a preprocessor problem called a circular include. This problem occurs when the header file for a class A #includes the header file for a class B and vice versa. Some preprocessors are not be able to resolve such #include directives, causing a compilation error. If class A, for example, uses only a reference to an object of class B, then the #include in class A's header file can be replaced by a forward declaration of class B to prevent the circular include.
Figure 9.26. Adding operations to the Withdrawal class header file.
(This item is displayed on pages 514 - 515 in the print version)
1 // Fig. 9.26: Withdrawal.h 2 // Definition of class Withdrawal that represents a withdrawal transaction 3 #ifndef WITHDRAWAL_H 4 #define WITHDRAWAL_H 5 6 class Screen; // forward declaration of class Screen 7 class Keypad; // forward declaration of class Keypad 8 class CashDispenser; // forward declaration of class CashDispenser 9 class BankDatabase; // forward declaration of class BankDatabase 10 11 class Withdrawal 12 { 13 public: 14 // operations 15 void execute(); // perform the transaction 16 private: 17 // attributes 18 int accountNumber; // account to withdraw funds from 19 double amount; // amount to withdraw 20 21 // references to associated objects 22 Screen &screen; // reference to ATM's screen 23 Keypad &keypad; // reference to ATM's keypad 24 CashDispenser &cashDispenser; // reference to ATM's cash dispenser 25 BankDatabase &bankDatabase; // reference to the account info database 26 }; // end class Withdrawal 27 28 #endif // WITHDRAWAL_H |
Software Engineering Observation 9.12
Several UML modeling tools can convert UML-based designs into C++ code, considerably speeding the implementation process. For more information on these "automatic" code generators, refer to the Internet and Web resources listed at the end of Section 2.8. |
This concludes our discussion of the basics of generating class header files from UML diagrams. In the final "Software Engineering Case Study" section (Section 3.11), we demonstrate how to modify the header files to incorporate the object-oriented concept of inheritance.
Software Engineering Case Study Self-Review Exercises
9.1 |
State whether the following statement is true or false, and if false, explain why: If an attribute of a class is marked with a minus sign (-) in a class diagram, the attribute is not directly accessible outside of the class. |
9.2 |
In Fig. 9.21, the association between the ATM and the Screen indicates that:
|
9.3 |
Write C++ code to begin implementing the design for class Account. |
Answers to Software Engineering Case Study Self-Review Exercises
9.1 |
True. The minus sign (-) indicates private visibility. We've mentioned "friendship" as an exception to private visibility. Friendship is discussed in Chapter 10. |
|
9.2 |
b. |
|
|
||
9.3 |
The design for class Account yields the header file in Fig. 9.27. Figure 9.27. Account class header file based on Fig. 9.20 and Fig. 9.21.
|
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