Overriding versus Overloading

Two very important concepts in object-oriented programming are overriding and overloading. Overloading is about creating multiple methods with the same name, but different signatures, in the same scope. Overriding is about changing the behavior of a certain method in the child class from the way it is behaving in the parent class. The rest of this article will explore these two concepts in detail.

Contributed by
Rating: 4 stars4 stars4 stars4 stars4 stars / 24
June 10, 2008
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

Overloading occurs when a method has more than one definition in the same scope. It's important to remember two key points from the previous statement: same name and same scope. The method implementations have the same name because they do similar tasks. For instance, if we need to implement a method that gets the student name, there are many ways to do that. We can get the name using an id and we can get the name using a social security number. One way to implement the methods is as follows:


  class   Student

{

...

public   string GetName( int id) {...}

public   string GetName( string ssn) {...}

...

}


The method GetName() is overloaded since the two implementations are in the same scope (class scope) and have the same name. If the methods are declared in different scopes (for example, different classes), then we are not talking about overloading.

The first question that comes to mind is: do we have to declare them with the same name? The answer is no. We could have named them GetName1() and GetName2(), or even GetNameById() and GetNameBySSN(). So overloading is not mandatory; it is just a helpful feature in object-oriented languages (like C++, Java, and C#). It is common sense since both methods are doing pretty much the same thing.

Because the methods have the same name, the compiler will use the signature to determine what method to call under different scenarios. The compiler will be able to tell the difference using the method signature, which has to do with the method parameters. Be definition, the method signature is the name of the method and its parameters. Since the name in this case is the same, what is left is the parameters. There are three ways to distinguish one set of parameters from the other:

  1. Parameter count - one method could have 2 parameters while the other has 3. This way, the compiler will call the method with the correct number of parameters.

  2. Parameter type - if two methods have the same parameter count, but different types (int, string, long …), then it is easy for the compiler to know which method to call.

  3. Parameter order - when we have a match in the parameter count and parameter type, but with a different order, then it is again easy for the compiler to know which method to call. For example:


public   string GetName( int id, string match) {...}

public   string GetName( string match, int id) {...}

Method Overloading Example

Here is a full example that illustrates method overloading:


namespace OverloadingMethods

{

class   Program

{

static   void Main( string [] args)

{

Point p1 = new   Point ();

Console .WriteLine( "p1 -> {0}" , p1);

p1.Move();

Console .WriteLine( "p1 -> {0}" , p1);

p1.Move(2);

Console .WriteLine( "p1 -> {0}" , p1);

p1.Move(4, 7);

Console .WriteLine( "p1 -> {0}" , p1);


Point p2 = new   Point (2, 5);

Console .WriteLine( "p2 -> {0}" , p2);

p2.Move(10, 9);

Console .WriteLine( "p2 -> {0}" , p2);

p2.Move();

Console .WriteLine( "p2 -> {0}" , p2);

}

}


class   Point

{

private   int x;

private   int y;

Random rand = new   Random ();


public Point()

{

x = y = 0;

}


public Point( int x_value, int y_value)

{

x = x_value;

y = y_value;

}


//Move x with a random number between 1 and 100 (inclusive)

//Move y with a random number between 1 and 50 (inclusive)

public   void Move()

{

x += rand.Next(1, 101);

y += rand.Next(1, 51);

}


//move x and y by the same number (delta)

public   void Move( int delta)

{

x += delta;

y += delta;

}


//move x and y by the specified values

public   void Move( int delta_x, int delta_y)

{

x += delta_x;

y += delta_y;

}


public   override   string ToString()

{

return   string .Format( "[{0},{1}]" , x, y);

}

}

}


Notice that the Point class is flexible in the way a point can be moved. By overloading the Move() method, we are able to move a point via different x and y values, via the same value (delta), or via random x and y values. This way, our class gives its user different ways of moving a point using the same friendly Move() method.

Overload a Constructor

In addition to overloading a method, we are also able to overload a constructor. In the same way we give the user different ways of calling a method, we can provide different ways to construct an object. In the Point class, we did just that when we created two constructors: a default constructor (no parameters) and a constructor that takes x and y values. Here is another example that illustrates the way we can overload a constructor:


namespace Overloading

{

class   Program

{

static   void Main( string [] args)

{

Fraction f1 = new   Fraction ();

Console .WriteLine(f1.ToString());

Fraction f2 = new   Fraction (3);

Console .WriteLine(f2.ToString());

Fraction f3 = new   Fraction (2, 5);

Console .WriteLine(f3.ToString());

}

}


class   Fraction

{

private   int num;

private   int denom;


//constructors

public Fraction()

{

num = denom = 1;

}


public Fraction( int n)

{

num = n;

denom = 1;

}


public Fraction( int n, int d)

{

num = n;

denom = d;

}


public   override   string ToString()

{

return   string .Format( "Fraction {0}/{1} = {2}" ,

num, denom, ( double )num / denom);

}

}

}


In the Fraction class, we provided three different constructors:

  1. public Fraction(): This is the default constructor. It allows the user to create the simplest fraction, 1 for the numerator and 1 for the denominator (1/1).

  2. public Fraction( int n): This constructor is similar to the previous one, but it allows the user to set the numerator (denominator still 1).

  3. public Fraction( int n, int d): This constructor gives the fullest flexibility because it allows the user to provide values for the numerator and the denominator.

Having these three constructors, now we can create different fractions based on our needs:


Fraction f1 = new   Fraction ();

Fraction f2 = new   Fraction (3);

Fraction f3 = new   Fraction (2, 5);


Final note: The return type method cannot be used in the method signature to distinguish one method call from the other. So the following is not considered overloading; it is actually a compile time error:


public   void Move( int delta_x, int delta_y) {...}

public   int Move( int delta_x, int delta_y) {...}


The only difference between the two methods is that one returns a void, and the other returns an int.

Overriding

As mentioned earlier, overriding has to do with parent and child classes. If you are not satisfied with the implementation of a method in the parent class, you can keep the same declaration (signature and return type), but provide a different implementation. For example, a Rectangle class inherits the drawing functionality from a Shape class, but it overrides this functionality in order to be able to draw a rectangle.

We have been using overriding all along in our examples. In C#, everything is an object, so when we create a class ( Employee , Fraction …) that does not specifically inherit from another class, it automatically inherits the functionality of an Object. Notice that in our previous examples, we were able to use the ToString() method to print an object as a string. The ToString() method is defined in the Object class. Since the Object class is too general, this method cannot give us anything useful, so we override it.

Ponder the following example:


namespace OverridingExample

{

class   Program

{

static   void Main( string [] args)

{

Employee e = new   Employee ( "Jim" , "Tester" , 38, 15.95);

Console .WriteLine(e);

Manager m = new   Manager ( "Jennifer" , "Jones" , 40, 25, 350);

Console .WriteLine(m);

}

}


class   Employee

{

protected   string firstName;

protected   string lastName;

protected   int hoursWorked;

protected   double ratePerHour;


public Employee( string f_name, string l_name,

int hours, double rate)

{

firstName = f_name;

lastName = l_name;

hoursWorked = hours;

ratePerHour = rate;

}


public   virtual   double CalculatePay()

{

return hoursWorked * ratePerHour;

}


public   override   string ToString()

{

return   string .Format( "Name: {0} {1}nPay: {2}" ,

firstName, lastName, CalculatePay());

}

}


class   Manager : Employee   //Manager inherits from Employee

{

private   double bonus;


public Manager( string f_name, string l_name,

int hours, double rate, double bonus)

: base (f_name, l_name, hours, rate)

{

this .bonus = bonus;

}


public   override   double CalculatePay()

{

return   base .CalculatePay() + bonus;

}

}

}


In the Employee class, we are overriding the ToString() method in order to print the Employee in a nicely formatted string (notice the keyword override in the method declaration). The Employee class did not specifically inherit from any class. So by default, it inherits from the Object class, and we are able to override the ToString() method. The CalculatePay() method calculates the Employee ’s pay (rate * hoursWorked).

In the Manager class, on the other hand, we did not override the ToString() method because the one inherited from the Employee class is sufficient. But a Manager’s pay is different from a regular Employee’s pay. Based on that, we can override the CalculatePay() method to account for the bonus. To make this work, however, we need to declare the CalculatePay() method in the Employee class as virtual (which means it is able to be overridden). Now, when we have a reference pointing to an Employee class, it will call that Employee’s CalculatePay() method. When that reference is pointing to a Manager class, it will call the Manager’s Calculatepay() method.

Conclusion

Overriding and overloading are very important features in an object-oriented language like C#. When used correctly, they can lead to very powerful and readable code. When we have methods with similar functionality, it is not necessary to give them different names when we can overload them instead. And when we are not satisfied with the functionality provided in a parent class, we can override the method to meet our needs.

blog comments powered by Disqus
C# ARTICLES

- Beginning C#
- ASP.NET RedirectPermanent Method using C# an...
- C Programming Language and UNIX Pioneer Pass...
- Using Facebook JavaScript SDK in ASP.NET wit...
- ASP.NET Export to Excel and Word using VB.NE...
- WAV and MP3 Streaming with ASP.Net and C#
- Game Programming using SDL: the File I/O API
- C# and Java Developer Jobs on the Rise
- The Future Evolution of C# and VB.NET
- C# If and Else-if Statements
- How To Use the C# String Replace Method
- 5 Ways to Parse XML in C#
- C# Meets Design Patterns
- Coding a CRC-Generating Algorithm in C
- Cyclic Redundancy Check

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
 
 
 

ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 6 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials