Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Polymorphism | OOP Principles
C# Beyond Basics
course content

Conteúdo do Curso

C# Beyond Basics

C# Beyond Basics

1. Additional Structures & File Handling
2. Structs & Enumerators
3. Introduction to Object-Oriented Programming (OOP)
4. OOP Essentials
5. OOP Principles

book
Polymorphism

The term Polymorphism means "occurring in several different forms". In the context of object-oriented programming, Polymorphism refers to the ability of a class to provide a common interface for its derived classes while allowing each derived class to implement specific behaviors for the inherited methods.

Normally when we are creating an object of a class, we create a variable to hold the reference of that object. And the type of the variable is usually the class of that object.

For-example:

cs

index

copy
123
Dog myVar = new Dog(); // or even in case of implicit declaration, 'myVar' will be of type 'Dog' var myVar = new Dog();

However, we can also create a variable of a base class and store an object of a derived class in it.

For example:

cs

index

copy
1234567891011121314151617181920212223242526272829303132
using System; class Mammal { public int age; public Mammal(int age) { this.age = age; } } class Dog : Mammal { public string breed; public Dog(int age, string breed) : base(age) { this.breed = breed; } } class ConsoleApp { static void Main() { Mammal example = new Dog(10, "Labrador"); Console.WriteLine(example.age); Console.WriteLine(example.breed); // Error because it's not accessible (read explanation below) } }

The breed attribute of the Dog object is not accessible because when we store the Dog object into a Mammal variable, it implicitly gets converted into Mammal. It means that we can only access the attributes and methods that are present in the Mammal class. It doesn't mean that the value stored in the breed class is lost, it is only inaccessible and we can say that it's essentially hidden.

We can simply convert example into a Dog through explicit typecasting and the breed attribute will become available again:

cs

index

copy
12345678910111213141516171819202122232425262728293031323334353637383940
using System; class Mammal { public int age; public Mammal(int age) { this.age = age; } public void speak() { // Empty for now } } class Dog : Mammal { public string breed; public Dog(int age, string breed) : base(age) { this.breed = breed; } } class ConsoleApp { static void Main() { Mammal example = new Dog(10, "Labrador"); Console.WriteLine(example.age); Dog casted = (Dog)example; Console.WriteLine(casted.breed); } }

However, for methods there is an additional feature called method overriding, which is somewhat similar to method overloading however we basically redefine a method from a base class in the derived class.

For example, we would want Mammal to have a method speak() such that it outputs Woof! if it's called from a Dog object, and Meow! if it is called from a Cat object:

cs

index

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
using System; class Mammal { public void speak() { Console.WriteLine("Mammal Speaks"); } } class Dog : Mammal { public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // The following execute the overriden version of the methods Dog d1 = new Dog(); d1.speak(); Cat c1 = new Cat(); c1.speak(); Mammal m1 = new Mammal(); Mammal m2 = new Cat(); Mammal m3 = new Dog(); // All of these execute the 'Mammal' version of the method m1.speak(); m2.speak(); m3.speak(); } }

The warnings we get in this compilation are due to overlapping names of methods in parent and child classes. In this case there is overlap between the speak methods of Cat and Mammal classes, and also between Dog and Mammal class, which is why we get two warnings.

However, notice in the end how m1, m2 and m3 execute the method defined in the Mammal class, it is because they are casted into Mammal objects.

If we want the speak method to behave the way it behaves in its original object then we can simply convert it into a virtual method. A virtual method is simply a method which allows us to override itself from derived classes in such a way that the specific implementation executed is determined at the runtime based on the type of the original object.

To make a method virtual, we simply add the virtual keyword before its return type:

cs

index

copy
1234567
class Mammal { public virtual void speak() { Console.WriteLine("Mammal Speaks"); } }

To make an overridden implementation of this method, we use the keyword override before the return type in the derived class' implementation of that new implementation:

cs

index

copy
123456789101112131415
class Dog : Mammal { public override void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { public override void speak() { Console.WriteLine("Meow!"); } }

Let's now put together the two snippets and see how it affects the output:

cs

index

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
using System; class Mammal { public virtual void speak() { Console.WriteLine("Mammal Speaks"); } } class Dog : Mammal { public override void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { public override void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { Mammal m1 = new Mammal(); Mammal m2 = new Cat(); Mammal m3 = new Dog(); m1.speak(); // Since it stores a Mammal() object, it executes the Mammal's implementation m2.speak(); // Output: Meow! m3.speak(); // Output: Woof! // The following behave the same as they did in the previous example: Dog d1 = new Dog(); d1.speak(); Cat c1 = new Cat(); c1.speak(); } }

You see that in the output, m2 and m3 use the Cat and Dog's implementation of the method because those objects were originally Cat and Dog. This whole process of overriding methods such that they behave based on their original type is called polymorphism.

One situation where this can be very useful is being able to store objects of multiple different data types into a single array or list.

For-example:

cs

index

copy
123456789
List<Shape> shapes = new List<Shape>(); shapes.Add(new Rectangle(25, 50)); shapes.Add(new Square(50)); shapes.Add(new Circle(10)); shapes[0].getArea(); // Output: 1250.0f shapes[1].getArea(); // Output: 2500.0f shapes[2].getArea(); // Output: 314.15f
1. What two keywords are used in method overriding?
2. What is the correct way of making a method overridable?
What two keywords are used in method overriding?

What two keywords are used in method overriding?

Selecione a resposta correta

What is the correct way of making a method overridable?

What is the correct way of making a method overridable?

Selecione a resposta correta

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 5. Capítulo 4
We're sorry to hear that something went wrong. What happened?
some-alt