Time Class Case Study: Overloaded Constructors

Time Class Case Study Overloaded Constructors

As you know, you can declare your own constructor to specify how objects of a class should be initialized. Next, we demonstrate a class with several overloaded constructors that enable objects of that class to be initialized in different ways. To overload constructors, simply provide multiple constructor declarations with different signatures. Recall from Section 7.12 that the compiler differentiates signatures by the number, types and order of the parameters in each signature.

Class Time2 with Overloaded Constructors

By default, instance variables hour, minute and second of class Time1 (Fig. 9.1) are initialized to their default values of 0 (which is midnight in universal time). Class Time1 does not enable the class's clients to initialize the time with specific non-zero values. Class Time2 (Fig. 9.7) contains five overloaded constructors for conveniently initializing its objects in a variety of ways. The constructors ensure that each Time2 object begins in a consistent state. In this application, four of the constructors invoke a fifth constructor, which in turn calls method SetTime. Method SetTime invokes the set accessors of properties Hour, Minute and Second, which ensure that the value supplied for hour is in the range 0 to 23 and that the values for minute and second are each in the range 0 to 59. If a value is out of range, it is set to 0 by the corresponding property (once again ensuring that each instance variable remains in a consistent state). The compiler invokes the appropriate constructor by matching the number and types of the arguments specified in the constructor call with the number and types of the parameters specified in each constructor declaration. Note that class Time2 also provides properties for each instance variable.

Figure 9.7. Time2 class declaration with overloaded constructors.

(This item is displayed on pages 421 - 422 in the print version)

 1 // Fig. 9.7: Time2.cs
 2 // Time2 class declaration with overloaded constructors.
 3 public class Time2
 4 {
 5 private int hour; // 0 - 23
 6 private int minute; // 0 - 59
 7 private int second; // 0 - 59
 8
 9 // Time2 parameterless constructor: initializes each instance variable
10 // to zero; ensures that Time2 objects start in a consistent state
11 public Time2() : this( 0, 0, 0 ) { }
12
13 // Time2 constructor: hour supplied, minute and second defaulted to 0
14 public Time2( int h ) : this( h, 0, 0 ) { }
15
16 // Time2 constructor: hour and minute supplied, second defaulted to 0
17 public Time2( int h, int m ) : this( h, m, 0 ) { }
18
19 // Time2 constructor: hour, minute and second supplied
20 public Time2( int h, int m, int s ) 
21 { 
22  SetTime( h, m, s ); // invoke SetTime to validate time
23 } // end Time2 three-parameter constructor 
24
25 // Time2 constructor: another Time2 object supplied
26 public Time2( Time2 time ) 
27  : this( time.Hour, time.Minute, time.Second ) { }
28
29 // set a new time value using universal time; ensure that
30 // the data remains consistent by setting invalid values to zero
31 public void SetTime( int h, int m, int s )
32 {
33 Hour = h; // set the Hour property
34 Minute = m; // set the Minute property
35 Second = s; // set the Second property
36 } // end method SetTime
37
38 // Properties for getting and setting
39 // property that gets and sets the hour
40 public int Hour
41 {
42 get
43 {
44 return hour;
45 } // end get
46 // make writing inaccessible outside the class
47 private set
48 {
49 hour = ( ( value >= 0 && value < 24 ) ? value : 0 );
50 } // end set
51 } // end property Hour
52 53 // property that gets and sets the minute 54 public int Minute 55 { 56 get 57 { 58 return minute; 59 } // end get 60 // make writing inaccessible outside the class 61 private set 62 { 63 minute = ( ( value >= 0 && value < 60 ) ? value : 0 ); 64 } // end set 65 } // end property Minute 66 67 // property that gets and sets the second 68 public int Second 69 { 70 get 71 { 72 return second; 73 } // end get 74 // make writing inaccessible outside the class 75 private set 76 { 77 second = ( ( value >= 0 && value < 60 ) ? value : 0 ); 78 } // end set 79 } // end property Second 80 81 // convert to string in universal-time format (HH:MM:SS) 82 public string ToUniversalString() 83 { 84 return string.Format( 85 "{0:D2}:{1:D2}:{2:D2}", Hour, Minute, Second ); 86 } // end method ToUniversalString 87 88 // convert to string in standard-time format (H:MM:SS AM or PM) 89 public override string ToString() 90 { 91 return string.Format( "{0}:{1:D2}:{2:D2} {3}", 92 ( ( Hour == 0 || Hour == 12 ) ? 12 : Hour % 12 ), 93 Minute, Second, ( Hour < 12 ? "AM" : "PM" ) ); 94 } // end method ToString 95 } // end class Time2

Class Time2's Constructors

Line 11 declares a parameterless constructora constructor invoked without arguments. Note that this constructor has an empty body, as indicated by the empty set of curly braces after the constructor header. Instead, we introduce a use of the this reference that is allowed only in the constructor's header. In line 11, the usual constructor header is followed by a colon (:), then the keyword this. The this reference is used in method-call syntax (along with the three int arguments) to invoke the Time2 constructor that takes three int arguments (lines 2023). The parameterless constructor passes values of 0 for the hour, minute and second to the constructor with three int parameters. The use of the this reference as shown here is called a constructor initializer. Constructor initializers are a popular way to reuse initialization code provided by one of the class's constructors rather than defining similar code in another constructor's body. We use this syntax in four of the five Time2 constructors to make the class easier to maintain. If we needed to change how objects of class Time2 are initialized, only the constructor that the class's other constructors call would need to be modified. Even that constructor might not need modificationit simply calls the SetTime method to perform the actual initialization, so it is possible that the changes the class might require would be localized to this method.

Line 14 declares a Time2 constructor with a single int parameter representing the hour, which is passed with 0 for the minute and second to the constructor at lines 2023. Line 17 declares a Time2 constructor that receives two int parameters representing the hour and minute, which are passed with 0 for the second to the constructor at lines 2023. Like the parameterless constructor, each of these constructors invokes the constructor at lines 2023 to minimize code duplication. Lines 2023 declare the Time2 constructor that receives three int parameters representing the hour, minute and second. This constructor calls SetTime to initialize the instance variables to consistent values. SetTime, in turn, invokes the set accessors of properties Hour, Minute and Second.

Common Programming Error 9 4

A constructor can call methods of the class. Be aware that the instance variables might not yet be in a consistent state, because the constructor is in the process of initializing the object. Using instance variables before they have been initialized properly is a logic error.

Lines 2627 declare a Time2 constructor that receives a Time2 reference to another Time2 object. In this case, the values from the Time2 argument are passed to the threeparameter constructor at lines 2023 to initialize the hour, minute and second. Note that line 27 could have directly accessed the hour, minute and second instance variables of the constructor's time argument with the expressions time.hour, time.minute and time.secondeven though hour, minute and second are declared as private variables of class Time2.

Software Engineering Observation 9 4

When one object of a class has a reference to another object of the same class, the first object can access all the second object's data and methods (including those that are private).

 

Notes Regarding Class Time2's Methods, Properties and Constructors

Note that Time2's properties are accessed throughout the body of the class. In particular, method SetTime assigns values to properties Hour, Minute and Second in lines 3335, and methods ToUniversalString and ToString use properties Hour, Minute and Second in line 85 and lines 9293, respectively. In each case, these methods could have accessed the class's private data directly without using the properties. 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 4 bytes of memory). If we make such a change, only the bodies of the methods that access the private data directly would need to changein particular, the individual properties Hour, Minute and Second. There would be no need to modify the bodies of methods SetTime, ToUniversalString or ToString, because they do not access the private data directly. Designing the class in this manner reduces the likelihood of programming errors when altering the class's implementation.

Similarly, each Time2 constructor could be written to include a copy of the appropriate statements from method SetTime. Doing so may be slightly more efficient, because the extra constructor call and the call to SetTime are eliminated. However, duplicating statements in multiple methods or constructors makes changing the class's internal data representation more difficult and error-prone. Having the Time2 constructors call the three-parameter constructor (or even call SetTime directly) requires any changes to the implementation of SetTime to be made only once.

Software Engineering Observation 9 5

When implementing a method of a class, use the class's properties to access the class's private data. This simplifies code maintenance and reduces the likelihood of errors.

Also notice that class Time2 takes advantage of access modifiers to ensure that clients of the class must use the appropriate methods and properties to access private data. In particular, the properties Hour, Minute and Second declare private set accessors (lines 47, 61 and 75, respectively) to restrict the use of the set accessors to members of the class. We declare these private for the same reasons that we declare the instance variables privateto simplify code maintenance and ensure that the data remains in a consistent state. Although the methods in class Time2 still have all the advantages of using the set accessors to perform validation, clients of the class must use the SetTime method to modify this data. The get accessors of properties Hour, Minute and Second are implicitly declared public because their properties are declared publicwhen there is no access modifier before a get or set accessor, the accessor inherits the access modifier preceding the property name.

Using Class Time2's Overloaded Constructors

Class Time2Test (Fig. 9.8) creates six Time2 objects (lines 914) to invoke the overloaded Time2 constructors. Line 9 shows that the parameterless constructor (line 11 of Fig. 9.7) is invoked by placing an empty set of parentheses after the class name when allocating a Time2 object with new. Lines 1014 of the application demonstrate passing arguments to the other Time2 constructors. C# invokes the appropriate overloaded constructor by matching the number and types of the arguments specified in the constructor call with the number and types of the parameters specified in each constructor declaration. Line 10 invokes the constructor at line 14 of Fig. 9.7. Line 11 invokes the constructor at line 17 of Fig. 9.7. Lines 1213 invoke the constructor at lines 2023 of Fig. 9.7. Line 14 invokes the constructor at lines 2627 of Fig. 9.7. The application displays the string representation of each initialized Time2 object to confirm that each was initialized properly.

Figure 9.8. Overloaded constructors used to initialize Time2 objects.

(This item is displayed on pages 425 - 426 in the print version)

 1 // Fig. 9.8: Time2Test.cs
 2 // Overloaded constructors used to initialize Time2 objects.
 3 using System;
 4
 5 public class Time2Test
 6 {
 7 public static void Main( string[] args )
 8 {
 9 Time2 t1 = new Time2(); // 00:00:00 
10 Time2 t2 = new Time2( 2 ); // 02:00:00 
11 Time2 t3 = new Time2( 21, 34 ); // 21:34:00 
12 Time2 t4 = new Time2( 12, 25, 42 ); // 12:25:42
13 Time2 t5 = new Time2( 27, 74, 99 ); // 00:00:00
14 Time2 t6 = new Time2( t4 ); // 12:25:42 
15
16 Console.WriteLine( "Constructed with:
" );
17 Console.WriteLine( "t1: all arguments defaulted" );
18 Console.WriteLine( " {0}", t1.ToUniversalString() ); // 00:00:00
19 Console.WriteLine( " {0}
", t1.ToString() ); // 12:00:00 AM
20
21 Console.WriteLine(
22 "t2: hour specified; minute and second defaulted" );
23 Console.WriteLine( " {0}", t2.ToUniversalString() ); // 02:00:00
24 Console.WriteLine( " {0}
", t2.ToString() ); // 2:00:00 AM
25
26 Console.WriteLine(
27 "t3: hour and minute specified; second defaulted" );
28 Console.WriteLine( " {0}", t3.ToUniversalString() ); // 21:34:00
29 Console.WriteLine( " {0}
", t3.ToString() ); // 9:34:00 PM
30
31 Console.WriteLine( "t4: hour, minute and second specified" );
32 Console.WriteLine( " {0}", t4.ToUniversalString() ); // 12:25:42
33 Console.WriteLine( " {0}
", t4.ToString() ); // 12:25:42 PM
34
35 Console.WriteLine( "t5: all invalid values specified" );
36 Console.WriteLine( " {0}", t5.ToUniversalString() ); // 00:00:00
37 Console.WriteLine( " {0}
", t5.ToString() ); // 12:00:00 AM
38
39 Console.WriteLine( "t6: Time2 object t4 specified" );
40 Console.WriteLine( " {0}", t6.ToUniversalString() ); // 12:25:42
41 Console.WriteLine( " {0}", t6.ToString() ); // 12:25:42 PM
42 } // end Main
43 } // end class Time2Test
 
 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

 t6: Time2 object t4 specified
 12:25:42
 12:25:42 PM

Default and Parameterless Constructors

Preface

Index

    Introduction to Computers, the Internet and Visual C#

    Introduction to the Visual C# 2005 Express Edition IDE

    Introduction to C# Applications

    Introduction to Classes and Objects

    Control Statements: Part 1

    Control Statements: Part 2

    Methods: A Deeper Look

    Arrays

    Classes and Objects: A Deeper Look

    Object-Oriented Programming: Inheritance

    Polymorphism, Interfaces & Operator Overloading

    Exception Handling

    Graphical User Interface Concepts: Part 1

    Graphical User Interface Concepts: Part 2

    Multithreading

    Strings, Characters and Regular Expressions

    Graphics and Multimedia

    Files and Streams

    Extensible Markup Language (XML)

    Database, SQL and ADO.NET

    ASP.NET 2.0, Web Forms and Web Controls

    Web Services

    Networking: Streams-Based Sockets and Datagrams

    Searching and Sorting

    Data Structures

    Generics

    Collections

    Appendix A. Operator Precedence Chart

    Appendix B. Number Systems

    Appendix C. Using the Visual Studio 2005 Debugger

    Appendix D. ASCII Character Set

    Appendix E. Unicode®

    Appendix F. Introduction to XHTML: Part 1

    Appendix G. Introduction to XHTML: Part 2

    Appendix H. HTML/XHTML Special Characters

    Appendix I. HTML/XHTML Colors

    Appendix J. ATM Case Study Code

    Appendix K. UML 2: Additional Diagram Types

    Appendix L. Simple Types

    Index



    Visual C# How to Program
    Visual C# 2005 How to Program (2nd Edition)
    ISBN: 0131525239
    EAN: 2147483647
    Year: 2004
    Pages: 600

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