Overloading Methods and Constructors

Often, you'll want to have more than one function with the same name. The most common example of this is to have more than one constructor. In the examples shown so far, the constructor has taken a single parameter: a DateTime object. It would be convenient to be able to set new Time objects to an arbitrary time by passing in year, month, date, hour, minute, and second values. It would be even more convenient if some clients could use one constructor, and other clients could use the other constructor. Function overloading provides for these exact contingencies.

The signature of a method is defined by its name and its parameter list.. Parameter lists can differ by having different numbers or different types of parameters. For example, in the following code, the first method differs from the second in the number of parameters, and the second differs from the third in the types of parameters:

void myMethod(int p1);
void myMethod(int p1, int p2);
void myMethod(int p1, string s1);

A class can have any number of methods, as long as each one's signature differs from that of all the others.

Overloaded methods may have different return types, but changing only the return type does not change the signature, and thus is not sufficient to overload the method.

void myMethod(int p1);
string myMethod(int p1, int p2);  // legal

void otherMethod(int p1);
string otherMethod(int p1);  // not legal

In the snippet shown here, myMethod is overloaded by changing the number of parameters, and the two versions may have different return types. On the other hand, the signature of otherMethod is unchanged in the two versions, and changing the return type is not enough to overload the method.

Example 4-10 illustrates the Time class with two constructors: one that takes a DateTime object, and the other that takes six integers.

Example 4-10. Overloading the constructor

using System;

namespace OverloadedConstructor
{
  public class Time
  {
    // private member variables
    private int Year;
    private int Month;
    private int Date;
    private int Hour;
    private int Minute;
    private int Second;

    // public accessor methods
    public void DisplayCurrentTime(  )
    {
      Console.WriteLine( "{0}/{1}/{2} {3}:{4}:{5}",
        Month, Date, Year, Hour, Minute, Second );
    }

    // constructors
    public Time( System.DateTime dt )
    {
      Year = dt.Year;
      Month = dt.Month;
      Date = dt.Day;
      Hour = dt.Hour;
      Minute = dt.Minute;
      Second = dt.Second;
    }

    public Time( int Year, int Month, int Date,
      int Hour, int Minute, int Second )
    {
      this.Year = Year;
      this.Month = Month;
      this.Date = Date;
      this.Hour = Hour;
      this.Minute = Minute;
      this.Second = Second;
    }
  }

  public class Tester
  {
    static void Main(  )
    {
      DateTime currentTime = DateTime.Now;

      Time t1= new Time( currentTime );
      t.DisplayCurrentTime(  );

      Time t2 = new Time( 2007, 11, 18, 11, 03, 30 );
      t2.DisplayCurrentTime(  );

    }
  }
}
Output:

11/20/2007 17:7:54
11/18/2007 11:3:30

As you can see, the Time class in Example 4-10 has two constructors. If a function's signature consisted only of the function name, the compiler would not know which constructors to call when constructing t1 and t2. However, because the signature includes the function argument types, the compiler is able to match the constructor call for t1 with the constructor whose signature requires a DateTime object. Likewise, the compiler is able to associate the t2 constructor call with the constructor method whose signature specifies six integer arguments.

When you overload a method, you must change the signature (i.e., the name, number, or type of the parameters). You are free, as well, to change the return type, but this is optional. Changing only the return type doesn't overload the method, and creating two methods with the same signature but differing return types will generate a compile error, as you can see in Example 4-11.

Example 4-11. Varying the return type on overloaded methods

using System;

namespace VaryingReturnType
{
  public class Tester
  {
    private int Triple( int val )
    {
      return 3 * val;
    }

    private long Triple( long val )
    {
      return 3 * val;
    }

    public void Test(  )
    {
      int x = 5;
      int y = Triple( x );
      System.Console.WriteLine( "x: {0} y: {1}", x, y );

      long lx = 10;
      long ly = Triple( lx );
      System.Console.WriteLine( "lx: {0} ly: {1}", lx, ly );

    }
    static void Main(  )
    {
      Tester t = new Tester(  );
      t.Test(  );
    }
  }
}
Output:

x: 5 y: 15
lx: 10 ly: 30

In this example, the Tester class overloads the Triple( ) method, one to take an integer, the other to take a long. The return type for the two Triple( ) methods varies. Although this is not required, it is very convenient in this case.

Get Programming C# 3.0, 5th Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.