11.4. Polymorphism
Polymorphism means “many-shaped”, and it occurs when we have classes that are related to each other by inheritance. Polymorphism refers to the ability of a single interface to be used to refer to multiple implementations of a particular behavior (functionality or “method”).
In C#, polymorphism can be achieved through inheritance, interfaces, and virtual
methods. Inheritance allows us inheriting fields and methods from a base/parent class.
Polymorphism further allows use to modify and use those methods to perform different
tasks. This is called method overriding
, meaning to override the definition of the
method in the base/parent class. In this case here, you are implementing method name
that you inherit from a parent class, you have to use the same method signatures
.
There will be time when you need to define two or more methods sharing the same
method name in the same class (as opposing to method overriding, where method modification
happens in the child classes). For example, you want to create an “AddTwo” method in your
math operation class and you want AddTwo to intake integers, float, and decimal types.
This is a form of polymorphism [1] called method overloading,
in which you need to provide different method signatures
(such as data types) in
order to distinguish the methods.
11.4.1. Method Overriding: virtual/override/base
Think of a base class called Animal
that has a method called
animalSound()
. Derived classes of Animals could be Pig
, Cat
, Dog
- and they can have their own implementation of the same animalSound()
(the pig oinks, and the cat meows, etc.):
1class Animal // Base class (parent)
2{
3 public void animalSound()
4 {
5 Console.WriteLine("The animal makes a sound");
6 }
7}
8
9class Pig : Animal // Derived class (child)
10{
11 public void animalSound()
12 {
13 Console.WriteLine("The pig says: wee wee");
14 }
15}
16class Dog : Animal // Derived class (child)
17{
18 public void animalSound()
19 {
20 Console.WriteLine("The dog says: bow wow");
21 }
22}
23class Program
24{
25 static void Main(string[] args)
26 {
27 Animal myAnimal = new Animal(); // Create a Animal object
28 Animal myPig = new Pig(); // Create a Pig object
29 Animal myDog = new Dog(); // Create a Dog object
30 myAnimal.animalSound(); // The animal makes a sound
31 myPig.animalSound(); // The animal makes a sound
32 myDog.animalSound(); // The animal makes a sound
33 myCat.animalSound(); // The animal makes a sound
34 }
35}
The code output above is not what you expected. Different animals should make different sounds, but here Pig and Dog are making the same sound. This happens because the base class method overrides the derived class method, when they share the same name.
For the derived (child) to override
the base class method, you need to
add the
virtual
keyword to the method in the base class; anduse the
override
keyword for each derived class methods.
1class Animal // Base class (parent)
2{
3 public virtual void animalSound() // virtual
4 {
5 Console.WriteLine("The animal makes a sound");
6 }
7}
8
9class Pig : Animal // Derived class (child)
10{
11 public override void animalSound() // override
12 {
13 Console.WriteLine("The pig says: wee wee");
14 }
15}
16
17class Dog : Animal // Derived class (child)
18{
19 public override void animalSound() // override
20 {
21 Console.WriteLine("The dog says: bow wow");
22 }
23}
24
25class Cat : Animal // Derived class (child)
26{
27 public void animalSound()
28 {
29 animalSound();
30 // or base.animalSound(); // the base keyword refer
31 }
32}
33
34
35class Program
36{
37 static void Main(string[] args)
38 {
39 Animal myAnimal = new Animal(); // Create a Animal object
40 Animal myPig = new Pig(); // Create a Pig object
41 Animal myDog = new Dog(); // Create a Dog object
42 Animal myDog = new Cat(); // Create a Cat object
43
44 myAnimal.animalSound(); // The animal makes a sound
45 myPig.animalSound(); // The pig says: wee wee
46 myDog.animalSound(); // The dog says: bow wow
47 myCat.animalSound(); // The animal makes a sound
48 }
49}
Now you have achieved method overriding by marking the method in the base class
virtual
and the method in the derived class override
.
Note
The content in this section discuss advanced scenarios and is here for your reference.
In C#, there are a few rules to follow when using polymorphism: [2]
A class can only inherit from a single base class, but it can implement multiple interfaces.
A method marked as
virtual
in the base class can be overridden in a derived class using theoverride
keyword.If a derived class wants to call the implementation of a virtual method from the base class, it can use the
base
keyword.If a derived class wants to prevent a virtual method from being overridden in further derived classes, it can use the
sealed
keyword.If a derived class wants to provide its own implementation of a virtual method, but also wants to call the implementation from the base class, it can use the
base
keyword in the implementation.
1public class Shape
2{
3 public virtual void Draw()
4 {
5 Console.WriteLine("Drawing a shape");
6 }
7}
8
9public class Circle : Shape
10{
11 public override void Draw()
12 {
13 base.Draw(); // Call the implementation in the base class
14 Console.WriteLine("Drawing a circle");
15 }
16}
17
18public class Rectangle : Shape
19{
20 public sealed override void Draw() // note the "sealed" keyword
21 {
22 Console.WriteLine("Drawing a rectangle");
23 }
24}
25
26public class Triangle : Shape
27{
28 public override void Draw()
29 {
30 Console.WriteLine("Drawing a triangle");
31 }
32}
33
34public class Square : Rectangle
35{
36 // This will cause a compile-error because the Draw method is sealed in the Rectangle class
37 public override void Draw()
38 {
39 Console.WriteLine("Drawing a square");
40 }
41}
11.4.2. Method Overloading
With method overloading, multiple methods can have the same name with different signatures/parameters.
For example, consider the following example, which your use two methods that add numbers of different data types: [3]
static int PlusMethodInt(int x, int y)
{
return x + y;
}
static double PlusMethodDouble(double x, double y)
{
return x + y;
}
static void Main(string[] args)
{
int myNum1 = PlusMethodInt(8, 5);
double myNum2 = PlusMethodDouble(4.3, 6.26);
Console.WriteLine("Int: " + myNum1);
Console.WriteLine("Double: " + myNum2);
}
Obviously you are performing the same operations in the preceding code, with the only
difference been the data types. So, instead of creating two different methods, you may
overload
a PlusMethod
method to work for both int and double:
static int PlusMethod(int x, int y)
{
return x + y;
}
static double PlusMethod(double x, double y)
{
return x + y;
}
static void Main(string[] args)
{
int myNum1 = PlusMethod(8, 5);
double myNum2 = PlusMethod(4.3, 6.26);
Console.WriteLine("Int: " + myNum1);
Console.WriteLine("Double: " + myNum2);
}
Now, with method overloading, you can call PlusMethod()
with different data
types (int or double) and C# will choose the correct method to run according to their
signatures even if both methods have the same name.
Another example below shows you that, in addition to data types, you may even change the
number of parameters or even the operators (the +
in the fourth Add()
method
means).
namespace IntroCSCS
{
class MethodOverLoading
{
public int Add(int num1, int num2)
{
return (num1 + num2);
}
public int Add(int num1, int num2, int num3)
{
return (num1 + num2 + num3);
}
public float Add(float num1, float num2)
{
return (num1 + num2);
}
public string Add(string value1, string value2)
{
return (value1 + " " + value2);
}
}
}
namespace IntroCSCS
{
class Program
{
static void Main(string[] args)
{
MethodOverloading mol = new MethodOverloading();
Console.WriteLine("Add two int parameter: " + mol.Add(3, 2));
Console.WriteLine("Add three int parameter: " + mol.Add(3, 2, 8));
Console.WriteLine("Add two float parameter: " + mol.Add(3f, 22f));
Console.WriteLine("Add two string parameter: " + mol.Add("hello", "world")); }
// output:
// Add two int parameter: 5
// Add three int parameter: 13
// Add two float parameter: 25
// Add two string parameter: hello world
}
}
Footnotes