Overloading Constructors


Like methods, constructors can also be overloaded. Doing so allows you to construct objects in a variety of ways. For example, consider the following program:

 // Demonstrate an overloaded constructor. using System; class MyClass {   public int x;   public MyClass() {     Console.WriteLine("Inside MyClass().");     x = 0;   }   public MyClass(int i) {     Console.WriteLine("Inside MyClass(int).");     x = i;   }   public MyClass(double d) {     Console.WriteLine("Inside MyClass(double).");     x = (int) d;   }   public MyClass(int i, int j) {     Console.WriteLine("Inside MyClass(int, int).");     x = i * j;   } } class OverloadConsDemo {   public static void Main() {     MyClass t1 = new MyClass();     MyClass t2 = new MyClass(88);     MyClass t3 = new MyClass(17.23);     MyClass t4 = new MyClass(2, 4);     Console.WriteLine("t1.x: " + t1.x);     Console.WriteLine("t2.x: " + t2.x);     Console.WriteLine("t3.x: " + t3.x);     Console.WriteLine("t4.x: " + t4.x);   } }

The output from the program is shown here:

 Inside MyClass(). Inside MyClass(int). Inside MyClass(double). Inside MyClass(int, int). t1.x: 0 t2.x: 88 t3.x: 17 t4.x: 8

MyClass( ) is overloaded four ways, each constructing an object differently. The proper constructor is called based upon the parameters specified when new is executed. By overloading a class’ constructor, you give the user of your class flexibility in the way objects are constructed.

One of the most common reasons that constructors are overloaded is to allow one object to initialize another. For example, here is an enhanced version of the Stack class developed earlier that allows one stack to be constructed from another:

 // A stack class for characters. using System; class Stack {   // these members are private   char[] stck; // holds the stack   int tos;     // index of the top of the stack   // Construct an empty Stack given its size.   public Stack(int size) {     stck = new char[size]; // allocate memory for stack     tos = 0;   }   // Construct a Stack from a stack.   public Stack(Stack ob) {     // allocate memory for stack     stck = new char[ob.stck.Length];     // copy elements to new stack     for(int i=0; i < ob.tos; i++)       stck[i] = ob.stck[i];     // set tos for new stack     tos = ob.tos;   }   // Push characters onto the stack.   public void push(char ch) {     if(tos==stck.Length) {       Console.WriteLine(" -- Stack is full.");       return;     }     stck[tos] = ch;     tos++;   }   // Pop a character from the stack.   public char pop() {     if(tos==0) {       Console.WriteLine(" -- Stack is empty.");       return (char) 0;     }     tos--;     return stck[tos];   }   // Return true if the stack is full.   public bool full() {     return tos==stck.Length;   }   // Return true if the stack is empty.   public bool empty() {     return tos==0;   }   // Return total capacity of the stack.   public int capacity() {     return stck.Length;   }   // Return number of objects currently on the stack.   public int getNum() {     return tos;   } } // Demonstrate the Stack class. class StackDemo {   public static void Main() {     Stack stk1 = new Stack(10);     char ch;     int i;     // Put some characters into stk1.     Console.WriteLine("Push A through J onto stk1.");     for(i=0; !stk1.full(); i++)       stk1.push((char) ('A' + i));     // Create a copy of stck1     Stack stk2 = new Stack(stk1);     // Display the contents of stk1.     Console.Write("Contents of stk1: ");     while( !stk1.empty() ) {       ch = stk1.pop();       Console.Write(ch);     }     Console.WriteLine();     Console.Write("Contents of stk2: ");     while ( !stk2.empty() ) {       ch = stk2.pop();       Console.Write(ch);     }     Console.WriteLine("\n");   } }

The output is shown here:

 Push A through J onto stk1. Contents of stk1: JIHGFEDCBA Contents of stk2: JIHGFEDCBA

In StackDemo, the first stack, stk1, is constructed and filled with characters. This stack is then used to construct the second stack, stk2. This causes the following Stack constructor to be executed:

 // Construct a Stack from a stack. public Stack(Stack ob) {   // allocate memory for stack   stck = new char[ob.stck.Length];   // copy elements to new stack   for(int i=0; i < ob.tos; i++)     stck[i] = ob.stck[i];   // set tos for new stack   tos = ob.tos; }

Inside this constructor, an array is allocated that is long enough to hold the elements contained in the stack passed in ob. Then, the contents of ob’s array are copied to the new array, and tos is set appropriately. After the constructor finishes, the new stack and the original stack are separate, but identical.

Invoking an Overloaded Constructor Through this

When working with overloaded constructors, it is sometimes useful for one constructor to invoke another. In C#, this is accomplished by using another form of the this keyword. The general form is shown here:

 constructor-name(parameter-list1) : this(parameter-list2) {   // ... body of constructor, which may be empty }

When the constructor is executed, the overloaded constructor that matches the parameter list specified by parameter-list2 is first executed. Then, if there are any statements inside the original constructor, they are executed. Here is an example:

 // Demonstrate invoking a constructor through this. using System; class XYCoord {   public int x, y;   public XYCoord() : this(0, 0) {     Console.WriteLine("Inside XYCoord()");   }   public XYCoord(XYCoord obj) : this(obj.x, obj.y) {     Console.WriteLine("Inside XYCoord(obj)");   }   public XYCoord(int i, int j) {     Console.WriteLine("Inside XYCoord(int, int)");     x = i;     y = j;   } } class OverloadConsDemo {   public static void Main() {     XYCoord t1 = new XYCoord();     XYCoord t2 = new XYCoord(8, 9);     XYCoord t3 = new XYCoord(t2);     Console.WriteLine("t1.x, t1.y: " + t1.x + ", " + t1.y);     Console.WriteLine("t2.x, t2.y: " + t2.x + ", " + t2.y);     Console.WriteLine("t3.x, t3.y: " + t3.x + ", " + t3.y);   } }

The output from the program is shown here:

 Inside XYCoord(int, int) Inside XYCoord() Inside XYCoord(int, int) Inside XYCoord(int, int) Inside XYCoord(obj) t1.x, t1.y: 0, 0 t2.x, t2.y: 8, 9 t3.x, t3.y: 8, 9

Here is how the program works. In the XYCoord class, the only constructor that actually initializes the x and y fields is XYCoord(int, int). The other two constructors simply invoke XYCoord(int, int) through this. For example, when object t1 is created, its constructor, XYCoord( ), is called. This causes this(0, 0) to be executed, which in this case translates into a call to XYCoord(0, 0). The creation of t2 works in similar fashion.

One reason why invoking overloaded constructors through this can be useful is that it can prevent the unnecessary duplication of code. In the foregoing example, there is no reason for all three constructors to duplicate the same initialization sequence, which the use of this avoids. Another advantage is that you can create constructors with implied “default arguments” that are used when these arguments are not explicitly specified. For example, you could create another XYCoord constructor as shown here:

 public XYCoord(int x) : this(x, x) { }

This constructor automatically defaults the y coordinate to the same value as the x coordinate. Of course, it is wise to use such “default arguments” carefully because their misuse could easily confuse users of your classes.




C# 2.0(c) The Complete Reference
C# 2.0: The Complete Reference (Complete Reference Series)
ISBN: 0072262095
EAN: 2147483647
Year: 2006
Pages: 300

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