Case Study: A Date Class

Case Study A Date Class

The program of Figs. 11.1211.14 demonstrates a Date class. The class uses overloaded prefix and postfix increment operators to add 1 to the day in a Date object, while causing appropriate increments to the month and year if necessary. The Date header file (Fig. 11.12) specifies that Date's public interface includes an overloaded stream insertion operator (line 11), a default constructor (line 13), a setDate function (line 14), an overloaded prefix increment operator (line 15), an overloaded postfix increment operator (line 16), an overloaded += addition assignment operator (line 17), a function to test for leap years (line 18) and a function to determine whether a day is the last day of the month (line 19).

Figure 11.12. Date class definition with overloaded increment operators.

 1 // Fig. 11.12: Date.h
 2 // Date class definition.
 3 #ifndef DATE_H
 4 #define DATE_H
 5
 6 #include 
 7 using std::ostream;
 8
 9 class Date
10 {
11 friend ostream &operator<<( ostream &, const Date & );
12 public:
13 Date( int m = 1, int d = 1, int y = 1900 ); // default constructor
14 void setDate( int, int, int ); // set month, day, year
15 Date &operator++(); // prefix increment operator 
16 Date operator++( int ); // postfix increment operator
17 const Date &operator+=( int ); // add days, modify object
18 bool leapYear( int ) const; // is date in a leap year?
19 bool endOfMonth( int ) const; // is date at the end of month?
20 private:
21 int month;
22 int day;
23 int year;
24
25 static const int days[]; // array of days per month
26 void helpIncrement(); // utility function for incrementing date
27 }; // end class Date
28
29 #endif

Function main (Fig. 11.14) creates three Date objects (lines 1113)d1 is initialized by default to January 1, 1900; d2 is initialized to December 27, 1992; and d3 is initialized to an invalid date. The Date constructor (defined in Fig. 11.13, lines 1114) calls setDate to validate the month, day and year specified. An invalid month is set to 1, an invalid year is set to 1900 and an invalid day is set to 1.

Figure 11.13. Date class member- and friend-function definitions.

(This item is displayed on pages 610 - 611 in the print version)

 1 // Fig. 11.13: Date.cpp
 2 // Date class member-function definitions.
 3 #include 
 4 #include "Date.h"
 5
 6 // initialize static member at file scope; one classwide copy
 7 const int Date::days[] =
 8 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
 9
10 // Date constructor
11 Date::Date( int m, int d, int y )
12 {
13 setDate( m, d, y );
14 } // end Date constructor
15
16 // set month, day and year
17 void Date::setDate( int mm, int dd, int yy )
18 {
19 month = ( mm >= 1 && mm <= 12 ) ? mm : 1;
20 year = ( yy >= 1900 && yy <= 2100 ) ? yy : 1900;
21
22 // test for a leap year
23 if ( month == 2 && leapYear( year ) )
24 day = ( dd >= 1 && dd <= 29 ) ? dd : 1;
25 else
26 day = ( dd >= 1 && dd <= days[ month ] ) ? dd : 1;
27 } // end function setDate
28
29 // overloaded prefix increment operator 
30 Date &Date::operator++() 
31 { 
32  helpIncrement(); // increment date 
33  return *this; // reference return to create an lvalue
34 } // end function operator++ 
35
36 // overloaded postfix increment operator; note that the 
37 // dummy integer parameter does not have a parameter name
38 Date Date::operator++( int ) 
39 { 
40  Date temp = *this; // hold current state of object 
41  helpIncrement(); 
42 
43  // return unincremented, saved, temporary object 
44  return temp; // value return; not a reference return 
45 } // end function operator++ 
46
47 // add specified number of days to date
48 const Date &Date::operator+=( int additionalDays )
49 {
50 for ( int i = 0; i < additionalDays; i++ )
51 helpIncrement();
52
53 return *this; // enables cascading
54 } // end function operator+=
55
56 // if the year is a leap year, return true; otherwise, return false
57 bool Date::leapYear( int testYear ) const
58 {
59 if ( testYear % 400 == 0 ||
60 ( testYear % 100 != 0 && testYear % 4 == 0 ) )
61 return true; // a leap year
62 else
63 return false; // not a leap year
64 } // end function leapYear
65
66 // determine whether the day is the last day of the month
67 bool Date::endOfMonth( int testDay ) const
68 {
69 if ( month == 2 && leapYear( year ) )
70 return testDay == 29; // last day of Feb. in leap year
71 else
72 return testDay == days[ month ];
73 } // end function endOfMonth
74
75 // function to help increment the date
76 void Date::helpIncrement()
77 {
78 // day is not end of month
79 if ( !endOfMonth( day ) )
80 day++; // increment day
81 else
82 if ( month < 12 ) // day is end of month and month < 12
83 {
84 month++; // increment month
85 day = 1; // first day of new month
86 } // end if
87 else // last day of year
88 {
89 year++; // increment year
90 month = 1; // first month of new year
91 day = 1; // first day of new month
92 } // end else
93 } // end function helpIncrement
94
95 // overloaded output operator
96 ostream &operator<<( ostream &output, const Date &d )
97 {
98 static char *monthName[ 13 ] = { "", "January", "February",
99 "March", "April", "May", "June", "July", "August",
100 "September", "October", "November", "December" };
101 output << monthName[ d.month ] << ' ' << d.day << ", " << d.year;
102 return output; // enables cascading
103 } // end function operator<<

Figure 11.14. Date class test program.

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

 1 // Fig. 11.14: fig11_14.cpp
 2 // Date class test program.
 3 #include 
 4 using std::cout;
 5 using std::endl;
 6
 7 #include "Date.h" // Date class definition
 8
 9 int main()
10 {
11 Date d1; // defaults to January 1, 1900
12 Date d2( 12, 27, 1992 ); // December 27, 1992
13 Date d3( 0, 99, 8045 ); // invalid date
14
15 cout << "d1 is " << d1 << "
d2 is " << d2 << "
d3 is " << d3;
16 cout << "

d2 += 7 is " << ( d2 += 7 );
17
18 d3.setDate( 2, 28, 1992 );
19 cout << "

 d3 is " << d3;
20 cout << "
++d3 is " << ++d3 << " (leap year allows 29th)";
21
22 Date d4( 7, 13, 2002 );
23
24 cout << "

Testing the prefix increment operator:
"
25  << " d4 is " << d4 << endl; 
26 cout << "++d4 is " << ++d4 << endl; 
27 cout << " d4 is " << d4; 
28
29 cout << "

Testing the postfix increment operator:
"
30  << " d4 is " << d4 << endl; 
31 cout << "d4++ is " << d4++ << endl; 
32 cout << " d4 is " << d4 << endl; 
33 return 0;
34 } // end main
 
 d1 is January 1, 1900
 d2 is December 27, 1992
 d3 is January 1, 1900

 d2 += 7 is January 3, 1993

 d3 is February 28, 1992
 ++d3 is February 29, 1992 (leap year allows 29th)

 Testing the prefix increment operator:
 d4 is July 13, 2002
 ++d4 is July 14, 2002
 d4 is July 14, 2002

 Testing the postfix increment operator:
 d4 is July 14, 2002
 d4++ is July 14, 2002
 d4 is July 15, 2002
 

Lines 1516 of main output each of the constructed Date objects, using the overloaded stream insertion operator (defined in Fig. 11.13, lines 96103). Line 16 of main uses the overloaded operator += to add seven days to d2. Line 18 uses function setDate to set d3 to February 28, 1992, which is a leap year. Then, line 20 preincrements d3 to show that the date increments properly to February 29. Next, line 22 creates a Date object, d4, which is initialized with the date July 13, 2002. Then line 26 increments d4 by 1 with the overloaded prefix increment operator. Lines 2427 output d4 before and after the preincrement operation to confirm that it worked correctly. Finally, line 31 increments d4 with the overloaded postfix increment operator. Lines 2932 output d4 before and after the postincrement operation to confirm that it worked correctly.

Overloading the prefix increment operator is straightforward. The prefix increment operator (defined in Fig. 11.13, lines 3034) calls utility function helpIncrement (defined in Fig. 11.13, lines 7693) to increment the date. This function deals with "wraparounds" or "carries" that occur when we increment the last day of the month. These carries require incrementing the month. If the month is already 12, then the year must also be incremented and the month must be set to 1. Function helpIncrement uses function endOfMonth to increment the day correctly.

The overloaded prefix increment operator returns a reference to the current Date object (i.e., the one that was just incremented). This occurs because the current object, *this, is returned as a Date &. This enables a preincremented Date object to be used as an lvalue, which is how the built-in prefix increment operator works for fundamental types.

Overloading the postfix increment operator (defined in Fig. 11.13, lines 3845) is trickier. To emulate the effect of the postincrement, we must return an unincremented copy of the Date object. For example, that int variable x has the value 7, the statement

 cout << x++ << endl;

outputs the original value of variable x. So we'd like our postfix increment operator to operate the same way on a Date object. On entry to operator++, we save the current object (*this) in temp (line 40). Next, we call helpIncrement to increment the current Date object. Then, line 44 returns the unincremented copy of the object previously stored in temp. Note that this function cannot return a reference to the local Date object temp, because a local variable is destroyed when the function in which it is declared exits. Thus, declaring the return type to this function as Date & would return a reference to an object that no longer exists. Returning a reference (or a pointer) to a local variable is a common error for which most compilers will issue a warning.





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

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