Learn about Abstract Classes, Polymorphism & Operator Overloading in C#



In the previous article, you learned that methods in a base class can be overridden in child (inherited) classes to provide a new or a more specific implementation. But sometimes you need to force the child class to provide an implementation. I hear you saying “You can use an interface to achieve this goal”. True, an interface is a good candidate. But in some cases, you don’t the child class to implement all the methods in the base class; you want only some of them to be like this. In this case, you ought to use abstract classes.

Abstract classes

An abstract class in one that provides one or more abstract methods. An abstract method is prefixed by the keyword abstract, and it does not provide any implementation (no method body). It is just the method name and a semicolon. An abstract class may contain one or more methods that are non-abstract. Let’s convert our vehicle class to an abstract one:

We prefixed the class definition with the “abstract” keyword, then we defined one abstract method stop(). This method must be implemented in any child class. This makes sense; a car for example may implement this method as “vehicle is parking”, while a ship does not park, instead it may “dock”. Ok, let’s create classes for a Car and a Ship:

Not let’s call them in our Main() method:

The output will be:

Notice here that we didn’t (and needn’t) override the move() method although it was created in an abstract class because it was not declared as an “abstract”. As mentioned, this is one of the key differences between an interface and an abstract class.


“Poly” means multiple and morph means “form” so the term together basically means “multiple forms”. In C# polymorphism is two folded: static and dynamic. Static polymorphism is done at compile time. We’ve already seen examples to this when we used the same method name with different parameters (overloading). Sometimes it’s also called “early binding”.

You have also experienced dynamic polymorphism when you used “method overriding”; the same method name and parameters but different implementation. This is also referred to as “late binding” or compile-time polymorphism.

Another usefulnessof late binding is that you can treat objects that belong to different classes, which inherit from a common base class as one. So for example, let’s modify the Vehicle class to be non-abstract, add a virtual (overridable) move() method, and override this method in the car class:

Now let’s instantiate our objects:

Note how we assigned the myVehicle object to myCar, although both of them belong to different classes. But because the Car class inherits from Vehicle, this assignment is legal. However, you can no longer use any new methods created in the Car class once you assigned the myCar object to myVehicle; as you are now bound to the methods offered in Vehicle class only. That is, you cannot use the horn() method. Running this code will give the following output:

Operator overloading

Overloading is not restricted to methods only; you can also overload operators. As a matter of fact, you’ve been already overloading operators since the start of this series. Remember when you used the plus sign (+) to concatenate two strings together? That’s one form of operator overloading. In the following example, we are defining a new field in our Car class: price. We are overloading the plus operator to give us the total price of two more cars:

Notice how we defined the operator method: it must be public and static. It returns an object (typically the same class you are using). You add two or more parameters to be used with the plus sign. Inside the method you can place whatever code you like, provided that it returns the correct object type.

In the Main() function you can use your brand new operator as follows:

The output of this code will be 30000 which represents the total price of both cars.


In this article, we started by discussing abstract classes and the difference between them and the interfaces. Then we talked about polymorphism and how it covers both method overriding and overloading. Then you were introduced to a special type of overloading: operator overloading and how you can use different operators for different purposes than their defaults.

In the next article, we will talk about Events, the cornerstone of GUI programming. An important topic that deserves waiting for.

I hope you enjoyed this article. Thanks for reading.


Please enter your comment!
Please enter your name here