Learn that overloaded methods have the same name and different formal argument lists; that the word polymorphism means something like one name, many forms; that polymorphism manifests itself in C# in the form of multiple methods having the same name; that polymorphism manifests itself in three distinct forms in C#: method overloading, method overriding through class inheritance, and method overriding through interface inheritance.
Published: January 25, 2010
Validated with Amaya
By Richard G. Baldwin
XNA Programming Notes # 0110
|
This tutorial lesson is part of a continuing series dedicated to programming with the XNA Game Studio. I am writing this series of lessons primarily for the benefit of students enrolled in an introductory XNA game programming course that I teach. However, everyone is welcome to study and benefit from the lessons.
An earlier lesson titled Getting Started (see Resources) provided information on how to get started programming with Microsoft's XNA Game Studio. (See Baldwin's XNA programming website in Resources.)
The three main characteristics of an object-oriented program
Object-oriented programs exhibit three main characteristics:
I have explained encapsulation and inheritance in previous lessons. I will begin the explanation of polymorphism in this lesson. However, polymorphism is a complex topic and several lessons will be required to complete the explanation.
I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.
I recommend that you also study the other lessons in my extensive collection of online programming tutorials. You will find a consolidated index at www.DickBaldwin.com.
What is polymorphism?
The meaning of the word polymorphism is something like one name, many forms.
How does C# implement polymorphism?
Polymorphism manifests itself in C# in the form of multiple methods having the same name.
In some cases, multiple methods have the same name, but have different formal argument lists. These are overloaded methods.
In other cases, multiple methods have the same name, same return type, and same formal argument list. These are overridden methods.
This lesson concentrates on the use of method overloading to achieve compile-time polymorphism.
The class named Object
As you learned in an earlier lesson, every class in C# is a direct or indirect subclass of the class named Object. Methods defined in the Object class are inherited into all other classes. Some of those inherited methods may be overridden to make their behavior more appropriate for objects instantiated from the new subclasses. However, this lesson is not about overriding methods. Instead it is about overloading methods. I will cover method overriding in future lessons.
Multiple methods with the same name
Overloaded methods have the same name and different formal argument lists. They may or may not have the same return type.
Polymorphism manifests itself in C# in the form of multiple methods having the same name. As mentioned above, this lesson concentrates on method overloading, sometimes referred to as compile-time polymorphism. Subsequent lessons concentrate on method overriding, sometimes referred to as runtime polymorphism.
Compile-time and runtime polymorphism, what's the difference?
During the compilation and execution of polymorphic code, the compiler and the runtime system must decide which of two or more methods having the same name in the same scope must be executed. With method overloading, that decision is made when the program is compiled. With method overriding, that decision is deferred and made at runtime. Hence we have the terms compile-time polymorphism and runtime polymorphism.
Every class extends some other class
Every class in C# (except for the class named Object) extends some other class. If you don't explicitly specify the class that your new class extends, it will automatically extend the class named Object.
A class hierarchy
Thus, all classes in C# exist in a class hierarchy where the class named Object forms the root of the hierarchy.
Some classes extend Object directly, while other classes are subclasses of Object further down the hierarchy (they extend classes, which extend classes, which extend Object).
Methods in the Object class
You learned in an earlier lesson that the class named Object defines default versions of the following methods and that every class in the hierarchy inherits them:
Some methods are overloaded
The two methods named Equals are defined as overloaded methods in the Object class. (They have the same name and different formal argument lists.)
Some are meant to be overridden
Some of these methods are intended to be overridden for various purposes. This includes GetHashCode, and ToString.
Some are meant to be used as is
However, some of the methods, such as GetType, are intended to be used as is without overriding.
Three distinct forms of polymorphism
From a practical programming viewpoint, polymorphism manifests itself in three distinct forms in C#:
Method overloading
I will begin the discussion of polymorphism with method overloading, which is the simplest of the three. I will cover method overloading in this lesson and will cover polymorphism based on overridden methods using class inheritance and interface inheritance in future lessons.
Duplicate method names
C# allows you to have two or more method definitions in the same scope with the same name, provided that they have different formal argument lists. This is method overloading.
Compile-time polymorphism
Some authors refer to method overloading as a form of compile-time polymorphism, as distinguished from run-time polymorphism. This distinction comes from the fact that, for each method call, the compiler determines which method (from a group of overloaded methods) will be executed. This decision is made when the program is compiled.
In contrast, with method overriding, the determination of which overridden method to execute isn't made until runtime.
Selection based on the argument list
In practice, with overloaded methods, the compiler simply examines the types, number, and order of the parameters being passed in a method call and selects the overloaded method having a matching formal argument list.
Keeping it short and simple
In these lessons on polymorphism, I will explain sample programs that are as short and as simple as I know how to make them, while still illustrating the important points regarding polymorphism. My objective is to make the polymorphic concepts as clear as possible without having those concepts clouded by other programming issues.
Because of their simplicity, these programs aren't likely to resemble problems that you will encounter in the real world. I will simply ask you to trust me when I tell you that polymorphism has enormous application in real world programming.
A sample program
I will explain a sample program named Polymorph01 to illustrate method overloading. A complete listing of the program is provided in Listing 4 near the end of the lesson.
Within the class and the hierarchy
Method overloading can occur both within a class definition, and vertically within the class inheritance hierarchy.
In other words, an overloaded method can be inherited into a class that defines other overloaded versions of the method.)
The program named Polymorph01 illustrates both aspects of method overloading.
Class B extends class A, which extends Object
Upon examination of the program, you will see that the class named A extends the class named Object. You will also see that the class named B extends the class named A.
The class named Polymorph01 is a driver class whose Main method exercises the methods defined in the classes named A and B.
Designed to illustrate method overloading
Once again, this program is not intended to correspond to any particular real-world scenario. Rather, it is a very simple program designed specifically to illustrate method overloading.
Will discuss in fragments
As usual, I will discuss this program in fragments. A complete listing is provided in Listing 4 near the end of the lesson.
The code in Listing 1 defines the class named A, which explicitly extends Object.
Listing 1. Class A from the project named Polymorph01. using System; class A : Object { public void m() { Console.WriteLine("m()"); }//end method m() }//end class A |
Redundant code
Recall that explicitly extending Object is not required (but it also doesn't hurt anything).
The class named A would extend the class named Object by default unless the class named A explicitly extends some other class.
The method named m()
The code in Listing 1 defines a method named m(). Note that this version of the method has an empty argument list (it doesn't receive any parameters when it is executed). The behavior of the method is simply to display a message indicating that it is executing.
The class named B
Listing 2 contains the definition for the class named B. This class extends the class named A and inherits the method named m defined in the class named A.
Listing 2. Class B from the project named Polymorph01. class B : A { public void m(int x) { Console.WriteLine("m(int x)"); }//end method m(int x) //---------------------------------// public void m(String y) { Console.WriteLine("m(String y)"); }//end method m(String y) }//end class B |
Overloaded methods
In addition to the inherited method named m, the class named B defines two additional overloaded versions of the method named m:
Note that each of these versions of the method receives a single parameter and the type of the parameter is different in each case.
As with the version of the method having the same name defined in the class named A, the behavior of each of these two methods is simply to display a message indicating that it is executing.
The driver class
Listing 3 contains the definition of the driver class named Polymorph01.
Listing 3. Class Polymorph01 from the project named Polymorph01. public class Polymorph01 { public static void Main() { B var = new B(); var.m(); var.m(3); var.m("String"); //Pause until the user presses a key. Console.ReadKey(); }//end Main }//end class Polymorph01 |
Call all three overloaded methods
The code in the Main method
One version is inherited
The overloaded version of the method named m, defined in the class named A, is inherited into the class named B. Hence, it can be called on a reference to an object instantiated from the class named B.
Two versions defined in class B
The other two versions of the method named m are defined in the class named B. Thus, they also can be called on a reference to an object instantiated from the class named B.
The output
As you would expect from the code that you examined for each of the three methods, the output produced by sending messages to the object asking it to execute each of the three overloaded versions of the methods named m is shown in Figure 1.
Figure 1 Screen output
from the project named Polymorph01.
m() m(int x) m(String y) |
Parameters are not displayed
The values of the parameters passed to the methods do not appear in the output. In this program, the parameters are used solely to make it possible for the compiler to select the correct version of the overloaded method to execute in each case.
(In a real program, however, the parameters would normally be used by the code in the method for some useful purpose.)
This output confirms that each overloaded version of the method was properly selected for execution based on the matching of method parameters to the formal argument list of each method.
I encourage you to copy the code from Listing 4. Use that code to create a C# console project. Compile and run the project. Experiment with the code, making changes, and observing the results of your changes. Make certain that you can explain why your changes behave as they do.
Overloaded methods have the same name and different formal argument lists. They may or may not have the same return type.
The word polymorphism means something like one name, many forms. Polymorphism manifests itself in C# in the form of multiple methods having the same name.
Polymorphism manifests itself in three distinct forms in C#:
This lesson concentrates on method overloading, sometimes referred to as compile-time polymorphism.
A complete listing of the C# program discussed in this lesson is provided in Listing 4.Listing 4. Project Polymorph01. /*Project Polymorph01 Copyright 2009, R.G.Baldwin This program illustrates method overloading, both within a class, and up the inheritance hierarchy. Program output is: m() m(int x) m(String y) **************************************/ using System; class A : Object { public void m() { Console.WriteLine("m()"); }//end method m() }//end class A //===================================// class B : A { public void m(int x) { Console.WriteLine("m(int x)"); }//end method m(int x) //---------------------------------// public void m(String y) { Console.WriteLine("m(String y)"); }//end method m(String y) }//end class B //===================================// public class Polymorph01 { public static void Main() { B var = new B(); var.m(); var.m(3); var.m("String"); //Pause until the user presses // a key. Console.ReadKey(); }//end Main }//end class Polymorph01 |
Copyright 2009, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.
Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is object-oriented programming using Java and other OOP languages.
Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers.
In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.
-end-