Time Class Case Study: Constructors with Default Arguments

Time Class Case Study Constructors with Default Arguments

The program of Figs. 9.89.10 enhances class Time to demonstrate how arguments are implicitly passed to a constructor. The constructor defined in Fig. 9.2 initialized hour, minute and second to 0 (i.e., midnight in universal time). Like other functions, constructors can specify default arguments. Line 13 of Fig. 9.8 declares the Time constructor to include default arguments, specifying a default value of zero for each argument passed to the constructor. In Fig. 9.9, lines 1417 define the new version of the Time constructor that receives values for parameters HR, min and sec that will be used to initialize private data members hour, minute and second, respectively. Note that class Time provides set and get functions for each data member. The Time constructor now calls setTime, which calls the setHour, setMinute and setSecond functions to validate and assign values to the data members. The default arguments to the constructor ensure that, even if no values are provided in a constructor call, the constructor still initializes the data members to maintain the Time object in a consistent state. A constructor that defaults all its arguments is also a default constructori.e., a constructor that can be invoked with no arguments. There can be a maximum of one default constructor per class.



Figure 9.8. Time class containing a constructor with default arguments.

(This item is displayed on page 494 in the print version)

 1 // Fig. 9.8: Time.h
 2 // Declaration of class Time.
 3 // Member functions defined in Time.cpp.
 4
 5 // prevent multiple inclusions of header file
 6 #ifndef TIME_H
 7 #define TIME_H
 8
 9 // Time abstract data type definition
10 class Time
11 {
12 public:
13 Time( int = 0, int = 0, int = 0 ); // default constructor
14
15 // set functions
16 void setTime( int, int, int ); // set hour, minute, second
17 void setHour( int ); // set hour (after validation)
18 void setMinute( int ); // set minute (after validation)
19 void setSecond( int ); // set second (after validation)
20
21 // get functions
22 int getHour(); // return hour
23 int getMinute(); // return minute
24 int getSecond(); // return second
25
26 void printUniversal(); // output time in universal-time format
27 void printStandard(); // output time in standard-time format
28 private:
29 int hour; // 0 - 23 (24-hour clock format)
30 int minute; // 0 - 59
31 int second; // 0 - 59
32 }; // end class Time
33
34 #endif

Figure 9.9. Time class member-function definitions including a constructor that takes arguments.

(This item is displayed on pages 495 - 496 in the print version)

 1 // Fig. 9.9: Time.cpp
 2 // Member-function definitions for class Time.
 3 #include 
 4 using std::cout;
 5
 6 #include 
 7 using std::setfill;
 8 using std::setw;
 9
10 #include "Time.h" // include definition of class Time from Time.h
11
12 // Time constructor initializes each data member to zero;
13 // ensures that Time objects start in a consistent state 
14 Time::Time( int hr, int min, int sec ) 
15 { 
16  setTime( hr, min, sec ); // validate and set time 
17 } // end Time constructor 
18
19 // set new Time value using universal time; ensure that
20 // the data remains consistent by setting invalid values to zero
21 void Time::setTime( int h, int m, int s )
22 {
23 setHour( h ); // set private field hour
24 setMinute( m ); // set private field minute
25 setSecond( s ); // set private field second
26 } // end function setTime
27
28 // set hour value
29 void Time::setHour( int h )
30 {
31 hour = ( h >= 0 && h < 24 ) ? h : 0; // validate hour
32 } // end function setHour
33
34 // set minute value
35 void Time::setMinute( int m )
36 {
37 minute = ( m >= 0 && m < 60 ) ? m : 0; // validate minute
38 } // end function setMinute
39
40 // set second value
41 void Time::setSecond( int s )
42 {
43 second = ( s >= 0 && s < 60 ) ? s : 0; // validate second
44 } // end function setSecond
45
46 // return hour value
47 int Time::getHour()
48 {
49 return hour;
50 } // end function getHour
51
52 // return minute value
53 int Time::getMinute()
54 {
55 return minute;
56 } // end function getMinute
57
58 // return second value
59 int Time::getSecond()
60 {
61 return second;
62 } // end function getSecond
63
64 // print Time in universal-time format (HH:MM:SS)
65 void Time::printUniversal()
66 {
67 cout << setfill( '0' ) << setw( 2 ) << getHour() << ":"
68 << setw( 2 ) << getMinute() << ":" << setw( 2 ) << getSecond();
69 } // end function printUniversal
70
71 // print Time in standard-time format (HH:MM:SS AM or PM)
72 void Time::printStandard()
73 {
74 cout << ( ( getHour() == 0 || getHour() == 12 ) ? 12 : getHour() % 12 )
75 << ":" << setfill( '0' ) << setw( 2 ) << getMinute()
76 << ":" << setw( 2 ) << getSecond() << ( hour < 12 ? " AM" : " PM" );
77 } // end function printStandard

In Fig. 9.9, line 16 of the constructor calls member function setTime with the values passed to the constructor (or the default values). Function setTime calls setHour to ensure that the value supplied for hour is in the range 023, then calls setMinute and setSecond to ensure that the values for minute and second are each in the range 059. If a value is out of range, that value is set to zero (to ensure that each data member remains in a consistent state). In Chapter 16, Exception Handling, we throw exceptions to inform the user that a value is out of range, rather than simply assigning a default consistent value.


Note that the Time constructor could be written to include the same statements as member function setTime, or even the individual statements in the setHour, setMinute and setSecond functions. Calling setHour, setMinute and setSecond from the constructor may be slightly more efficient because the extra call to setTime would be eliminated. Similarly, copying the code from lines 31, 37 and 43 into constructor would eliminate the overhead of calling setTime, setHour, setMinute and setSecond. Coding the Time constructor or member function setTime as a copy of the code in lines 31, 37 and 43 would make maintenance of this class more difficult. If the implementations of setHour, setMinute and setSecond were to change, the implementation of any member function that duplicates lines 31, 37 and 43 would have to change accordingly. Having the Time constructor call setTime and having setTime call setHour, setMinute and setSecond enables us to limit the changes to code that validates the hour, minute or second to the corresponding set function. This reduces the likelihood of errors when altering the class's implementation. Also, the performance of the Time constructor and setTime can be enhanced by explicitly declaring them inline or by defining them in the class definition (which implicitly inlines the function definition).

Software Engineering Observation 9.9

If a member function of a class already provides all or part of the functionality required by a constructor (or other member function) of the class, call that member function from the constructor (or other member function). This simplifies the maintenance of the code and reduces the likelihood of an error if the implementation of the code is modified. As a general rule: Avoid repeating code.

Software Engineering Observation 9.10

Any change to the default argument values of a function requires the client code to be recompiled (to ensure that the program still functions correctly).

Function main in Fig. 9.10 initializes five Time objectsone with all three arguments defaulted in the implicit constructor call (line 11), one with one argument specified (line 12), one with two arguments specified (line 13), one with three arguments specified (line 14) and one with three invalid arguments specified (line 15). Then the program displays each object in universal-time and standard-time formats.


Figure 9.10. Constructor with default arguments.

(This item is displayed on pages 497 - 498 in the print version)

 1 // Fig. 9.10: fig09_10.cpp
 2 // Demonstrating a default constructor for class Time.
 3 #include 
 4 using std::cout;
 5 using std::endl;
 6
 7 #include "Time.h" // include definition of class Time from Time.h
 8
 9 int main()
10 {
11 Time t1; // all arguments defaulted 
12 Time t2( 2 ); // hour specified; minute and second defaulted 
13 Time t3( 21, 34 ); // hour and minute specified; second defaulted
14 Time t4( 12, 25, 42 ); // hour, minute and second specified 
15 Time t5( 27, 74, 99 ); // all bad values specified 
16
17 cout << "Constructed with:

t1: all arguments defaulted
 ";
18 t1.printUniversal(); // 00:00:00
19 cout << "
 ";
20 t1.printStandard(); // 12:00:00 AM
21
22 cout << "

t2: hour specified; minute and second defaulted
 ";
23 t2.printUniversal(); // 02:00:00
24 cout << "
 ";
25 t2.printStandard(); // 2:00:00 AM
26
27 cout << "

t3: hour and minute specified; second defaulted
 ";
28 t3.printUniversal(); // 21:34:00
29 cout << "
 ";
30 t3.printStandard(); // 9:34:00 PM
31
32 cout << "

t4: hour, minute and second specified
 ";
33 t4.printUniversal(); // 12:25:42
34 cout << "
 ";
35 t4.printStandard(); // 12:25:42 PM
36
37 cout << "

t5: all invalid values specified
 ";
38 t5.printUniversal(); // 00:00:00 
39 cout << "
 "; 
40 t5.printStandard(); // 12:00:00 AM 
41 cout << endl;
42 return 0;
43 } // end main
 
 Constructed with:

 t1: all arguments defaulted
 00:00:00
 12:00:00 AM

 t2: hour specified; minute and second defaulted
 02:00:00
 2:00:00 AM

 t3: hour and minute specified; second defaulted
 21:34:00
 9:34:00 PM

 t4: hour, minute and second specified
 12:25:42
 12:25:42 PM

 t5: all invalid values specified
 00:00:00
 12:00:00 AM
 

Notes Regarding Class Time's Set and Get Functions and Constructor

Time's set and get functions are called throughout the body of the class. In particular, function setTime (lines 2126 of Fig. 9.9) calls functions setHour, setMinute and setSecond, and functions printUniversal and printStandard call functions getHour, getMinute and getSecond in line 6768 and lines 7476, respectively. In each case, these functions could have accessed the class's private data directly without calling the set and get functions. However, consider changing the representation of the time from three int values (requiring 12 bytes of memory) to a single int value representing the total number of seconds that have elapsed since midnight (requiring only four bytes of memory). If we made such a change, only the bodies of the functions that access the private data directly would need to changein particular, the individual set and get functions for the hour, minute and second. There would be no need to modify the bodies of functions setTime, printUniversal or printStandard, because they do not access the data directly. Designing the class in this manner reduces the likelihood of programming errors when altering the class's implementation.

Similarly, the Time constructor could be written to include a copy of the appropriate statements from function setTime. Doing so may be slightly more efficient, because the extra constructor call and call to setTime are eliminated. However, duplicating statements in multiple functions or constructors makes changing the class's internal data representation more difficult. Having the Time constructor call function setTime directly requires any changes to the implementation of setTime to be made only once.

Common Programming Error 9.2

A constructor can call other member functions of the class, such as set or get functions, but because the constructor is initializing the object, the data members may not yet be in a consistent state. Using data members before they have been properly initialized can cause logic errors.


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



C++ How to Program
C++ How to Program (5th Edition)
ISBN: 0131857576
EAN: 2147483647
Year: 2004
Pages: 627

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net