1. Introduction
We learnt a lot about polymorphism and inheritance. In this article of the series “Diving in OOP”, we’ll discuss about the most hot and exciting topic of OOP in C#, i.e., Abstract Classes. The concept of Abstract classes is the same for any other language, but in C# we deal with it in a bit different way. Abstract classes play a different and very interesting role in polymorphism and inheritance. We’ll cover all the aspects of abstract classes with our hands-on lab and theory as an explanation to what output we get. We’ll also list down points to remember at the end of the article.
Pre-requisites
Wonder, we are dealing with the fourth part of our learning objective. Now my only expectation with my readers is to enjoy the series.
2. Roadmap
Let's recall our road map:
- Diving in OOP (Day 1): Polymorphism and Inheritance (Early Binding/Compile Time Polymorphism)
- Diving in OOP (Day 2): Polymorphism and Inheritance (Inheritance)
- Diving in OOP (Day 3): Polymorphism and Inheritance (Dynamic Binding/Run Time polymorphism)
- Diving in OOP (Day 4): Polymorphism and Inheritance (All about Abstract classes in C#)
- Diving in OOP (Day 5): All about access modifiers in C# (Public/Private/Protected/Internal/Sealed/Constants/Readonly Fields)
- Diving in OOP (Day 6): Understanding Enums in C# (A Practical Approach)
- Diving into OOP (Day 7): Properties in C# (A Practical Approach)
- Diving into OOP (Day 8): Indexers in C# (A Practical Approach)
- Diving inti OOP (Day 9): Understanding Events in C# (An Insight)
- Learning C# (Day 10): Delegates in C# (A Practical Approach)
- Learning C# (Day 11): Events in C# (A Practical Approach)
3. Abstract Classes
Let's get the definition from MSDN:
“The abstract keyword enables you to create classes and class members that are incomplete and must be implemented in a derived class. An abstract class cannot be instantiated. The purpose of an abstract class is to provide a common definition of a base class that multiple derived classes can share. For example, a class library may define an abstract class that is used as a parameter to many of its functions, and require programmers using that library to provide their own implementation of the class by creating a derived class.
Abstract classes may also define abstract methods. This is accomplished by adding the keyword abstract before the return type of the method.”
4. Abstract Classes in Action
Add a console application named “InheritanceAndPolymorphism
” in your Visual Studio. You’ll get a class named Program.cs, just add one more class named ClassA.cs, note that the ClassA
should be marked abstract
, and the following code to ClassA.cs and Program.cs:
using System;
namespace InheritanceAndPolymorphism
{
public abstract class ClassA
{
}
public class Program
{
private static void Main(string[] args)
{
ClassA classA = new ClassA();
Console.ReadKey();
}
}
}
Compile the code.
Output
Compile time error: Cannot create an instance of the abstract class or interface 'InheritanceAndPolymorphism.ClassA'
Point to remember: We cannot create an object of abstract
class using new
keyword.
Now we go into understanding the concept. No power can stop abstract
keyword to be written before a class. It acts as a modifier to the class. We cannot create an object of abstract
class using new
keyword. Seems that the class is useless for us as we cannot use it for other practical purposes as we used to do.
5. Non Abstract Method Definition in Abstract Class
Let's add some code to our abstract
class:
public abstract class ClassA
{
public int a;
public void XXX()
{
}
}
public class Program
{
private static void Main(string[] args)
{
ClassA classA = new ClassA();
Console.ReadKey();
}
}
We again see the error that we encountered earlier. Again, it reminds that we cannot use new
if we have already used an abstract
modifier.
6. Abstract Class Acting as a Base Class
Let's add one more class now:
public abstract class ClassA
{
public int a;
public void XXX()
{
}
}
public class ClassB:ClassA
{
}
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
We get no error? A class can be derived from abstract
class. Creating an object of ClassB
does not gives us any error.
Point to remember: A class can be derived from an abstract
class.
Point to remember: A object of a class derived from an abstract class can be created using new.
Note: Each and every code snippet written in this article is tried and tested.
7. Non Abstract Method Declaration in Abstract Class
Another scenario:
public abstract class ClassA
{
public int a;
public void XXX()
{
}
public void YYY();
}
public class ClassB:ClassA
{
}
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
We just declared a method named YYY()
in our abstract
class ClassA
.
Compile the code, we get:
Output
Compile time error: 'InheritanceAndPolymorphism.ClassA.YYY()'
must declare a body because it is not marked abstract, extern, or partial
InheritanceAndPolymorphism
is the namespace I used for my console application so you can ignore that, no need to confuse with the logic.
In the above code, we just added a method declaration in the abstract
class. An abstract
method indicates that the actual definition or code of the method is created somewhere else. The method prototype declared in abstract
class must also be declared abstract
as per the rules of C#.
8. Abstract Method Declaration in Abstract Class
Just make the method YYY()
as abstract
in ClassA
:
public abstract class ClassA
{
public int a;
public void XXX()
{
}
abstract public void YYY();
}
public class ClassB:ClassA
{
}
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
Output
Compiler error: 'InheritanceAndPolymorphism.ClassB' does not implement
inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY()'
Point to remember: If we declare any method as abstract
in our abstract
class, then it’s the responsibility of the derived class to provide the body of that abstract
method, unless a body is provided for that abstract
method, we cannot create an object of that derived class.
In the above mentioned scenario, we declared method YYY()
as abstract
in ClassA
. Since ClassB
derives from ClassA
, now it becomes the responsibility of ClassB
to provide the body of that abstract
method, else we cannot create an object of ClassB
.
9. Abstract Method Implementation in Derived Class
Now provide a body of method YYY()
in ClassB
. Let's see what happens:
public abstract class ClassA
{
public int a;
public void XXX()
{
}
abstract public void YYY();
}
public class ClassB:ClassA
{
public void YYY()
{
}
}
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
Everything seems fine now, but no? Compile the code, what we get:
Output
Two compile time errors this time:
Compile time error: 'InheritanceAndPolymorphism.ClassB' does not implement
inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY()'
Compile time warning: 'InheritanceAndPolymorphism.ClassB.YYY()' hides
inherited member 'InheritanceAndPolymorphism.ClassA.YYY()'.
To make the current member override that implementation, add the override
keyword. Otherwise add the new
keyword.
We have been continuously trying to compile our code, but no success till now. The compiler error indicates clearly that both of our base and derived class contains the same method named YYY()
.
If both our derived class and base class contain the method with the same name, always an error occurs. The only way to overcome this error is derived class explicitly add the modifier override to its method signature. We have already discussed such scenarios in our previous parts of the articles of Diving in OOP series.
Let's add the override
keyword before derived class method YYY()
.
public abstract class ClassA
{
public int a;
public void XXX()
{
}
abstract public void YYY();
}
public class ClassB:ClassA
{
public override void YYY()
{
}
}
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
We get no warning or error now?
10. Abstract Method Implementation in Derived Class with Different Return Type
Point to remember: When we override an abstract or a virtual
method from a derived class, we cannot change the parameters passed to it or the return type of that overridden method .
Let's just change the return type of the method YYY()
in derived class:
public abstract class ClassA
{
public int a;
public void XXX()
{
}
abstract public void YYY();
}
public class ClassB:ClassA
{
public override int YYY()
{
}
}
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
We changed return type of method YYY
from void
to int
in derived class. Compile the code.
Output
Compile time error: 'InheritanceAndPolymorphism.ClassB.YYY()': return type must be 'void'
to match overridden member 'InheritanceAndPolymorphism.ClassA.YYY()'
Therefore one more constraint.
Point to remember: An abstract
class means that the class is incomplete and cannot be directly used. An abstract
class can only be used as a base class for other classes to derive from.
Let's see the implementation of the second line mentioned in “point to remember”,
public abstract class ClassA
{
public int a;
public void XXX()
{
}
abstract public void YYY();
abstract public void YYY1();
abstract public void YYY2();
abstract public void YYY3();
}
public class ClassB:ClassA
{
public override void YYY()
{
}
}
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
Compiler error:
'InheritanceAndPolymorphism.ClassB' does not implement
inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY3()'
'InheritanceAndPolymorphism.ClassB' does not implement inherited
abstract member 'InheritanceAndPolymorphism.ClassA.YYY2()'
'InheritanceAndPolymorphism.ClassB' does not implement inherited
abstract member 'InheritanceAndPolymorphism.ClassA.YYY1()'
If we implement these three methods in derived class, we’ll get no error.
11. Variable Initialization in Abstract Class
Therefore as seen earlier, we get an error if we use a new
keyword on an abstract
class. If we do not initialize a variable in an abstract
class like we used a
, it will automatically have a default value of 0
which is what the compiler kept warning us about. We can initialize int
variable a
of ClassA
to any value we wish. The variables in abstract
class act similar to that in any other normal class.
12. Power of Abstract Class
Whenever a class remains incomplete, i.e., we do not have the code for some methods, we mark those methods abstract
and the class is marked abstract
as well. And so, we can compile our class without any error or blocker. Any other class can then derive from our abstract
class but they have to implement the abstract
, i.e., our incomplete methods from abstract
class.
Abstract
therefore enables us to write code for a part of the class and allows the others (derived classes) to complete the rest of the code.
13. Abstract Method in Non Abstract Class
Let's take another code block:
public class ClassA
{
public int a;
public void XXX()
{
}
abstract public void YYY();
}
public class ClassB:ClassA
{
public override void YYY()
{
}
}
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
Compile the code.
Output
Compiler error: 'InheritanceAndPolymorphism.ClassA.YYY()' is abstract
but it is contained in non-abstract class 'InheritanceAndPolymorphism.ClassA'
Note: Each and every code snippet written in this article is tried and tested.
We just removed abstract
keyword from class ClassA
. The error clearly conveys a message that if a single method is marked abstract
in a class, then the class will have to be abstract
as well.
Point to remember: If a class has even a single abstract
method, then the class has to be declared abstract
as well.
Point to remember: An abstract
method also cannot use the modifiers such as static
or virtual
.
We can only have the abstract
method in an abstract
class. Any class that derives from abstract
class has to give implementation to its abstract
method. By default, the modifier new
gets added to the derived class method, that makes it a new/different method.
14. Abstract Base Method
public abstract class ClassA
{
public int a;
public void XXX()
{
}
abstract public void YYY();
}
public class ClassB:ClassA
{
public override void YYY()
{
base.YYY();
}
}
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
Output
Compile time error : Cannot call an abstract base member:
'InheritanceAndPolymorphism.ClassA.YYY()'
We cannot call the method YYY()
from the base class ClassA
as it does not carry any implementation/code along with it and has also been declared abstract
. Common sense prevails? and C# off course does not allow us to call a method that does not contain code.
15. Abstract Class Acting as Derived as Well as Base Class
Let's modify our code a bit, and prepare our class structure something as follows:
public class ClassA
{
public virtual void XXX()
{
Console.WriteLine("ClassA XXX");
}
}
public abstract class ClassB:ClassA
{
public new abstract void XXX();
}
public class ClassC:ClassB
{
public override void XXX()
{
System.Console.WriteLine("ClassC XXX");
}
}
public class Program
{
private static void Main(string[] args)
{
ClassA classA = new ClassC();
ClassB classB = new ClassC();
classA.XXX(); classB.XXX();
}
}
Compile the code, and run.
Output
ClassA XXX
ClassC XXX
We created a base class named ClassA
that is not abstract
and added a virtual method XXX
to it. Since the method is non abstract
but marked virtual
so it has to be overridden in its deriving class. We added one more class named ClassB
and marked that class abstract
, note that this class is derived from ClassA
. So this class has a choice to override the method marked as virtual in base class. But we’ll do something different and tricky,
We marked XXX
method in this derived class as new abstract
, and did not give anybody to this method. Now what? We will add one more class ClassC
, that will derive from ClassB
. ClassC
has no choice but to override the method XXX
. Therefore we override the method XXX
in ClassC
.
In main method, we created two objects ClassA classA = new ClassC();
and ClassB classB = new ClassC();
First object looks like that of ClassC
but refers to ClassA
and second one again seems to be like ClassC
but refers to ClassB
.
In case of classA.XXX()
will definitely first look into the class ClassA
. Here, it finds the method XXX
marked as virtual. These kind of scenarios we have already taken n number of times in our earlier articles where we discussed about run time polymorphism . C# will then crawl over to class ClassB
. Here it gets shocked that the method XXX()
is abstract
, i.e., there is no code or implementation for method XXX()
and also that it is a method marked as new
, thus severing all links with the base class. And so flow halts and all and the method XXX()
from ClassA
gets executed.
In the case of b.XXX()()
, since the method is new
, the links to the base class gets broken, we are left with no choice but to invoke the method from ClassC
as it says override
.
We cannot replace the modifier new
with the keyword override
for the method XXX()
in abstract
class ClassB
.
Let's replace the override
modifier in ClassC
with “new
” like:
public class ClassC:ClassB
{
public new void XXX()
{
System.Console.WriteLine("ClassC XXX");
}
}
Output
Compile time error: 'InheritanceAndPolymorphism.ClassC' does not implement
inherited abstract member 'InheritanceAndPolymorphism.ClassB.XXX()'
The error indicates that as there is no code for the method XXX
. Remember the XXX()
of class ClassA
has nothing to do at all with that of ClassB
and ClassC
.
Also there is one more point to remember.
Point to remember: Virtual methods run slower that non virtual methods.
16. Can Abstract Class be Sealed?
Let's take this final question into our consideration. Let's test this too with an example.
public sealed abstract class ClassA
{
public abstract void XXX()
{
Console.WriteLine("ClassA XXX");
}
}
public class Program
{
private static void Main(string[] args)
{
}
}
Compile the code.
Output
Compile time error: 'InheritanceAndPolymorphism.ClassA':
an abstract class cannot be sealed or static
And so we get two points to remember.
Point to remember: Abstract
class cannot be sealed
class.
Point to remember: Abstract
class cannot be a static
class.
17. Points to Remember
Let's sum up all the points to remember:
- We cannot create an object of
abstract
class using new
keyword.
- A class can be derived from an
abstract
class.
- A object of a class derived from an abstract class can be created using new.
- If we declare any method as
abstract
in our abstract
class, then it’s the responsibility of the derived class to provide the body of that abstract
method, unless a body is provided for that abstract
method, we cannot create an object of that derived class.
- When we override an
abstract or a virtual
method from a derived class, we cannot change the parameters passed to it or the return type of that overridden method .
- An
abstract
class means that the class is incomplete and cannot be directly used. An abstract
class can only be used as a base class for other classes to derive from.
- If a class has even a single
abstract
method, then the class has to be declared abstract
as well.
- An
abstract
method also cannot use the modifiers such as static
or virtual
.
Virtual
methods run slower that non virtual methods.
Abstract
class cannot be sealed
class.
Abstract
class cannot be a static
class.
18. Conclusion
With this article, we complete our understanding of inheritance and polymorphism. We have covered almost all the aspects of Polymorphism and Inheritance. Abstract
classes are one of my favorites so I just wanted to take them separately. I hope my readers enjoyed this article too and learnt about abstract
classes in C#.
In my upcoming articles of the series, we’ll be discussing about other OOP features in the C# way with full hands-on lab and lot of discussion.
Keep coding and enjoy reading.
Also do not forget to rate/comment/like my article if it helped you by any means. This helps me to get motivated and encourages me to write more and more.
My other series of articles:
MVC: http://www.codeproject.com/Articles/620195/Learning-MVC-Part-Introduction-to-MVC-Architectu
RESTful WebAPIs: http://www.codeproject.com/Articles/990492/RESTful-Day-sharp-Enterprise-Level-Application
Happy coding !