Diving Into OOP (Day 2): Polymorphism and Inheritance

Introduction

In our first part of the article series, we learned about various scenarios of method overloading and did many interesting hands-on things too. My article in the second part of the series will focus solely on inheritance in OOP. Let's define inheritance using some bullet points.



Roadmap

We still stick to our roadmap that we defined before starting the series for learning OOP.


 Note: Each and every code snippet written in this article is tried and tested.


Inheritance in Action

OK. Let's do some hands-on. Create a console application and name it InheritanceAndPolymorphism. Add a class named ClassA and a class named ClassB, with the following code:

ClassA

class ClassA
{
}

ClassB

class
ClassB
{
   public int x = 100;
   public void Display1()
   {
      Console.WriteLine("ClassB Display1");
   }
   public void Display2()
   {
      Console.WriteLine("ClassB Display2");
   }
}

We see class ClassA is empty and we added two methods in the class ClassB, Display1 and Display2. We also have a variable x declared and defined with a value 100.

Now in the main method of Program.cs, write the following code:

Program.cs

class Program
{
   static void Main(string[] args)
   {
      ClassA a = new ClassA();
      a.Display1();
   }
}

If we run the code, we immediately result in the compile time error:

Error: 'InheritanceAndPolymorphism.ClassA' does not contain a definition for 'Display1' and no extension method 'Display1' accepting a first argument of type 'InheritanceAndPolymorphism.ClassA' could be found (are you missing a using directive or an assembly reference?)

That is very obvious, we don't have a definition of the Display1 method in ClassA, nor can we access the same method using a ClassA instance because it is not derived from any such class like ClassB that contains a Display1 method. The class ClassA does not contain any code or variable defined . An empty class does not throw any error as we are able to instantiate an object that looks like an instance of ClassA. The error comes about because the class ClassA has no method called Display1. However the class ClassB has a method named Display1. Guess how fun it could be if we are allowed to access all the code of classB from ClassA itself.

Just derive the class ClassA from ClassB using the ":" operator as in the code shown below:

ClassA

class ClassA:ClassB
{
}

ClassB

class ClassB
{
   public int x = 100;
   public void Display1()
   {
      Console.WriteLine("ClassB Display1");
   }
   public void Display2()
   {
      Console.WriteLine("ClassB Display2");
   }
}

Program.cs

class Program
{
   static void Main(string[] args)
   {
      ClassA a = new ClassA();
      a.Display1();
      Console.ReadKey();
   }
}

And now run the code as it was, we get an output now.

Output

ClassB Display1

In other words, now ClassA can access the inherited public methods of ClassB. The error vanishes and the Display1 in ClassB is invoked. If after the name of a class we specify : ClassB, in other words the name of another class then many changes occur at once. ClassA is now said to have been derived from ClassB. What that means is that all the code we wrote in ClassB can now be accessed and used in ClassA. It is if we actually wrote all the code that is contained in ClassB in ClassA. If we had created an instance that looks like that of ClassB then everything that the instance could do, now an instance of ClassA can also do. But we have not written a line of code in ClassA. We are made to believe that ClassA has one variable x and two functions Display1 and Display2 since ClassB contains these two functions. Therefore we enter into the concepts of inheritance where ClassB is the base class and ClassA is the derived class.



Let's use another scenario. Suppose we get into a situation where ClassA also has a method of the same name as of in ClassB. Let's define a method Derive1 in ClassA too, so our code for classA becomes:

class ClassA:ClassB
{
   public void Display1()
   {
      System.Console.WriteLine("ClassA Display1");
   }
}

ClassB

class ClassB
{
   public int x = 100;
   public void Display1()
   {
      Console.WriteLine("ClassB Display1");
   }
   public void Display2()
   {
      Console.WriteLine("ClassB Display2");
   }
}

Now if we run the application using the following code snippet for the Program class:

class Program
{
   static void Main(string[] args)
   {
      ClassA a = new ClassA();
      a.Display1();
      Console.ReadKey();
   }
}

The question is, what will happen now? What will be the output? Will there be any output or any compilation error. Ok, let's run it and we get the output:

ClassA Display1

But did you notice one thing, we also got a warning when we run the code,

Warning: 'InheritanceAndPolymorphism.ClassA.Display1()' hides inherited member 'InheritanceAndPolymorphism.ClassB.Display1()'. Use the new keyword if hiding was intended.

Point to remember: No one can stop a derived class from having a method with the same name already declared in its base class.

So, ClassA undoubtedly can contain the Display1 method, that is already defined with the same name in ClassB.
When we invoke a.Display1(), C# first checks whether the class ClassA has a method named Display1. If it does not find it, it checks in the base class. Earlier Display1 method was only available in the base class ClassB and hence got executed. Here since it is there in ClassA, it gets called from ClassA and not ClassB.

Point to remember: Derived classes get a first chance at execution, then the base class.

The reason for this is that the base class may have a number of mehtods and for various reasons we may not be satisfied with what they do. We should have the full right to have our copy of the method to be called. In other words the derived classes methods override the ones defined in the base class.

What happens if we call the base class Display1 method too with the base keyword in the derived class, in other words by using base.Display1(), so our ClassA code will be:

ClassA

class ClassA:ClassB
{
   public void Display1()
   {
      Console.WriteLine("ClassA Display1");
      base.Display1();
   }
}

ClassB

class ClassB
{
   public int x = 100;
   public void Display1()
   {
      Console.WriteLine("ClassB Display1");
   }
   public void Display2()
   {
      Console.WriteLine("ClassB Display2");
   }
}

Program.cs

class Program
{
   static void Main(string[] args)
   {
      ClassA a = new ClassA();
      a.Display1();
      Console.ReadKey();
   }
}

Output

ClassA Display1
ClassB Display1

We see here first our ClassA Display1 method is called and then the ClassB Display1 method.

Now if you want the best of both the classes then you may want to call the base classes (ClassB) Display1 first and then yours or vice versa. To do this, C# gives you a free keyword, called base. The keyword base can be used in any of derived class. It means call the method off the base class.

Thus base.Display1 will call the method Display1 from ClassB, the base class of ClassA as defined earlier.



Point to remember: A reserved keyword named “base” can be used in a derived class to call the base class method.

What if we call the Display2 method from the base class with an instance of the derived class ClassA?

/// <summary>
/// ClassB: acting as base class
/// </summary>
class ClassB
{
   public int x = 100;
   public void Display1()
   {
      Console.WriteLine("ClassB Display1");
   }
   public void Display2()
   {
      Console.WriteLine("ClassB Display2");
   }
}
/// <summary>
/// ClassA: acting as derived class
/// </summary>
class ClassA : ClassB
{
   public void Display1()
   {
      Console.WriteLine("ClassA Display1");
      base.Display2();
   }
}
/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
class Program
{
   static void Main(string[] args)
   {
      ClassA a = new ClassA();
      a.Display1();
      Console.ReadKey();
   }
}

Output

ClassA Display1
ClassB Display2

In the code above we only made just a small change, base.Display1 was replaced by base.Display2. In this specific scenario method Display2 from the class ClassB is called. Base is usually a very general purpose. It lets us access members of the base class from the derived class as explained earlier. We cannot use the base in ClassB since ClassB is not derived from any class as per our code. So its done that the base keyword can only be used in derived classes.

Let us use another case.

/// <summary>
/// ClassB: acting as base class
/// </summary>
class ClassB
{
   public int x = 100;
   public void Display1()
   {
      Console.WriteLine("ClassB Display1");
   }
}
/// <summary>
/// ClassA: acting as derived class
/// </summary>
class ClassA : ClassB
{
   public void Display2()
   {
      Console.WriteLine("ClassA Display2");
   }
}
/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
class Program
{
   static void Main(string[] args)
   {
      ClassB b = new ClassB();
      b.Display2();
      Console.ReadKey();
   }
}

Output

Error: 'InheritanceAndPolymorphism.ClassB' does not contain a definition for 'Display2' and no extension method 'Display2' accepting a first argument of type 'InheritanceAndPolymorphism.ClassB' could be found (are you missing a using directive or an assembly reference?)

Point to remember: Inheritance does not work backwards.

So we got an error. Since we see, ClassA is derived from ClassB, in other words ClassB is the base class. Therefore class ClassA can use all the members of class ClassB. Inheritance does not have backwords compatibility, whatever members ClassA contains does not permeate upwards to ClassB. When we tried to access the Display2 method of classA from the instance of class ClassB, it cannot provide it to class ClassB and thus an error occurs.

Point to remember: Except constructors and destructors, a class inherits everything from its base class.

If a class ClassC is derived from class ClassB, which in turn has been derived from class ClassA, then ClassC will inherit all the members declared in ClassB and also of ClassA. This is called transitive concept in inheritance. A derived class may inherit all the members of the base class but it cannot remove members off that base class. A derived class can however hide members of the base class by creating methods by the same name. The original member/method of the base class remains unmodified and unaffected by whatever happens in the derived class. It remains unchanged in the base class, in other words simply not visible in the derived class.

A class member could be of two types, in other words either a static member that directly belongs to a class or an instance member that is accessed through an instance of that class and belongs to that specific instance only. An instance member is accessible only through the object of the class and not directly by the class. The default member declared in the class are non-static, we just need to make them static using the static keyword.
All classes derive from a common base class named Object. So Object is the mother of all classes.

If we do not derive any class from any other class then it's the responsibility of C# to add: object by itself to the class definition. Object is the only class that is not derived from any other class. It is the ultimate base class for all the classes.

Suppose ClassA is derived from ClassB as in our case, but ClassB is not derived from any class.

public class ClassB
{
}
public class ClassA : ClassB
{
}

C# automatically adds :object to ClassB i.e., the code at compile time becomes,

public class ClassB:object
{
}
public class ClassA : ClassB
{
}

But as per theory we say ClassB is the direct base class of ClassA,so the classes of ClassA are ClassB and object.

Let's go for another case,

public class ClassW : System.ValueType
{
}
public class ClassX : System.Enum
{
}
public class ClassY : System.Delegate
{
}
public class ClassZ : System.Array
{
}

Here we have defined four classes, each derived from a built in class in C#, let's run the code.

We get many compile time errors as in the following:

Errors:

'InheritanceAndPolymorphism.ClassW' cannot derive from special class 'System.ValueType'
'InheritanceAndPolymorphism.ClassX' cannot derive from special class 'System.Enum'
'InheritanceAndPolymorphism.ClassY' cannot derive from special class 'System.Delegate'
'InheritanceAndPolymorphism.ClassZ' cannot derive from special class 'System.Array'


Don't be scared.



Did you notice the word special class. Our classes defined cannot inherit from special built-in classes in C#.

Point to remember: In inheritance in C#, custom classes cannot derive from special built-in C# classes like System.ValueType, System.Enum, System.Delegate, System.Array and so on.

One more case:

public class ClassW
{
}
public class ClassX
{
}
public class ClassY : ClassW, ClassX
{
}

In the preceding case, we see three classes, ClassW, ClassX and ClassY. ClassY is derived from ClassW and ClassX. Now if we run the code, what would we get?

Compile time Error: Class 'InheritanceAndPolymorphism.ClassY' cannot have multiple base classes: 'InheritanceAndPolymorphism.ClassW' and 'ClassX'

So one more Point to remember: A class can only be derived from one class in C#. C# does not support multiple inheritance by means of class*.

*Multiple inheritance in C# can be accomplished by the use of interfaces, we are not discussing interfaces in this article.

We are not allowed to derive from more than one class, thus every class can have only one base class.

In another case, suppose we try to write the following code:

public class ClassW:ClassY
{
}
public class ClassX:ClassW
{
}
public class ClassY : ClassX
{
}

The code is quite readable and simple, ClassW is derived from ClassY, ClassX is derived from ClassW, and ClassY in turn is derived from ClassX. So no problem of multiple inheritance, so our code should build successfully, let's compile the code.What do we get? Again a compile time error as in the following:

Error: Circular base class dependency involving 'InheritanceAndPolymorphism.ClassX' and 'InheritanceAndPolymorphism.ClassW'



Point to remember: Circular dependency is not allowed in inheritance in C#. ClassX is derived from ClassW that was derived from ClassY and ClassY was again derived from ClassX, that caused a circular dependency in three classes, yet that is logically impossible.

Equalizing the Instances/Objects

Let's directly start with a real case.

ClassB

public class ClassB
{
   public int b = 100;
}

ClassA

public class ClassA
{
   public int a = 100;
}

Program.cs

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
   private static void Main(string[] args)
   {
      ClassB classB = new ClassB();
      ClassA classA = new ClassA();
      classA = classB;
      classB = classA;
   }
}

We are here trying to equate two objects or two instances of each of two classes. Let's compile the code.

We get a compile-time error.

Error:

Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'
Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'

Inheritance And Polymorphism is the namespace that I used for my console application, so no need to be scared of that word, just ignore it.



C# works on rules, it will never allow you to equate objects of various independent classes to each other. Therefore we cannot equate an object classA of ClassA to classB of ClassB or vice versa. It does not matter whether the classes contain a similar structure and their variables are initialized to similar integer values, even if we do:

public class ClassB
{
   public int a = 100;
}
public class ClassA
{
   public int a = 100;
}

I just changed int b of ClassB to int a. In this case too, to equate an object is not allowed and not possible.

C# is also very particular when it comes to dealing with data types.

There is however one way to to this. By this way that we'll discuss, one of the errors will disappear. The only time we are allowed to equate dissimilar data types is only when we derive from them .Check out the code mentioned below. Let's discuss this in detail, when we create an object of ClassB by declaring new, we are creating two objects at one go, one that looks like ClassB and the other that looks like an object, in other words derived from the Object class (in other words ultimate base class). All classes in C# are finally derived from object. Since ClassA is derived from ClassB, when we declare new ClassA, we are creating 3 objects, one that looks like ClassB, one that looks like ClassA and finally that looks like the object class.

public class ClassB
{
   public int b = 100;
}
public class ClassA:ClassB
{
   public int a = 100;
}
/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
   private static void Main(string[] args)
   {
      ClassB classB = new ClassB();
      ClassA classA = new ClassA();
      classA = classB;
      classB = classA;
   }
}

We just derived ClassA from ClassB, this is something we can do, we learned a lot about this in this article. Now when we compile the code, we get:

Error: Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'. An explicit conversion exists (are you missing a cast?)

Like I said, C# is very particular about equating objects.

Thus when we write classA = classB, classA looks like ClassA instance, ClassB and object and classB looks like ClassB, there is a match at ClassB.Result? No error Smile | :) . Even though classB and classA have the same values, using classB we can only access the members of ClassB, even though had we used classA we could access ClassA also. We have devalued the potency of classB. The error occurs at classA = classB. The class ClassA has ClassB and more. We cannot have a base class on the right and a derived class on the left. classB only represents a ClassB whereas classA expects a ClassA which is a ClassA and ClassB.

Point to remember: We can equate an object of a base class to a derived class but not vice versa.

Another code snippet:

public class ClassB
{
   public int b = 100;
}
public class ClassA:ClassB
{
   public int a = 100;
}
/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
   private static void Main(string[] args)
   {
      ClassB classB = new ClassB();
      ClassA classA = new ClassA();
      classB=classA;
      classA = (ClassA)classB;
   }
}

Although we violated a C# rule of equating objects, we did not get any compiler error because of the cast we did to the object. A () is called a cast. Within the brackets the name of the class is put. A cast basically proves to be a great leveller. When we intend to write classA = classB, C# expects the right-hand side of the equal to to be a classA, in other words a ClassA instance . But it finds classB in other words a ClassB instance. So when we apply the cast , we actually try to convert an instance of ClassB to an instance of ClassA. This approach satisfies the rules of C# on only equating similar object types. Remember, it is only for the duration of the line that classB becomes a ClassA and not a ClassB.

Now if we remove ClassB as a base class to class ClassA as in following code and try to typecast classA to ClassB object then something happens.

public class ClassB
{
   public int b = 100;
}
Public class ClassA // Removed ClassB as base class
{
   public int a = 100;
}
/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
   private static void Main(string[] args)
   {
      ClassB classB = new ClassB();
      ClassA classA = new ClassA();
      classB = (ClassB)classA;
      classA = (ClassA)classB;
   }
}

Output

Error:
Cannot convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'
Cannot convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'


*'InheritanceAndPolymorphism' : Namespace I used in my application , so ignore that.

So we see that casting only works if one of the two classes is derived from one another. We cannot cast any two objects to each other.

The following is one last example.

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
   private static void Main(string[] args)
   {
      int integerA = 10;
      char characterB = 'A';
      integerA = characterB;
      characterB = integerA;
   }
}

We run the code,

Output

Error: Cannot implicitly convert type 'int' to 'char'. An explicit conversion exists (are you missing a cast?)

Point to remember:
We cannot implicitly convert an int to a char but a char can be converted to an int.

Conclusion

In this part of our article series we learned about inheritance. We took various scenarios and practical examples back to back for a deep to understanding. In my next article we'll be discussing runtime polymorphism. Inheritance plays a very important role in runtime polymorphism.

The following is a list of all our points to remember.

     

  1. No one can stop a derived class to have a method with the same name already declared in its base class.
  2. Derived classes get a first chance at execution, then the base class.
  3. A reserved keyword named “base” can be used in a derived class to call the base class method.
  4. Inheritance does not work backwards.
  5. Except constructors and destructors, a class inherits everything from its base class .
  6. In inheritance in C#, custom classes cannot derive from special built-in C# classes like System.ValueType, System.Enum, System.Delegate, System.Array and so on.
  7. A class can only be derived from one class in C#. C# does not support multiple inheritance by means of class.
  8. Circular dependency is not allowed in inheritance in C#. ClassX is derived from ClassW that was derived from ClassY and ClassY was again derived from ClassX, that caused circular dependency in three classes, that is logically impossible.
  9. We can equate an object of a base class to a derived class but not vice versa.
  10. We cannot implicitly convert an int into a char, but char can be converted to int.

You can read about compile time polymorphism in my first article of the series. Keep coding and learning.



Similar Articles