Inheritance

Inheritance is one of the main principles of any object-oriented programming. With inheritance, we can define attributes and functions that can be reused in child classes. In short, it helps us to reuse code written in the application across multiple modules. Let's go through an example to understand how inheritance helps us.

Let's consider two cars, CarA and CarB. From a very high-level perspective, we can think that both these classes will have similar features such as:

  • A brake function
  • An accelerator function
  • A car type; that is, diesel/petrol and so on
  • Color
  • Gear type

If we need to implement this in a C# application, one way would be to define them as two separate classes: CarA and CarB . However, the main concern with this approach is that both of these classes will need to have their own implementation of the shared features listed. Please refer the following code for how a possible implementation of CarA would look in C#:

public class CarA
{
public DateTime manufacturingDate;
public string bodyType;
public float fuelCapacity;
public void ImplementBrake()
{
Console.WriteLine("Inside Base Class Implement Brake");
}
public void ImplementAccelerator()
{
Console.WriteLine("Inside Base Class Implement Accelerator");
}
public void FoldableSeat()
{
Console.WriteLine("Inside Base Class Implement Accelerator");
}
}

Similarly, please refer to the following code for what a possible implementation of CarB would look like in C#:

public class CarB
{
public DateTime manufacturingDate;
public string bodyType;
public float fuelCapacity;
public void ImplementBrake()
{
Console.WriteLine("Inside Base Class Implement Brake");
}
public void ImplementAccelerator()
{
Console.WriteLine("Inside Base Class Implement Accelerator");
}
public void RoofTopExtendable()
{
Console.WriteLine("Inside Car B Foldable Seat");
}
}

This kind of implementation could have the following repercussions:

  • No code reuse: As you will understand from the preceding example, there are features that both CarA and CarB have in common. However, instead of maintaining common features separately, we are duplicating the code, which could cause maintenance issues as well.
  • Scalability: From a business/implementation perspective, there could be millions of different types of cars. Thus, for every new Car or a new common feature added to the Car implementation, we may face some scalability challenges in the application.

As clearly illustrated, change management in such applications would be a nightmare and would be very difficult to carry out.

Now we will use the concept of inheritance and see how the preceding scenario could be implemented in a better way. From an implementation perspective, we will be creating a base class, Car, which will have all of the common member variables across different implementations of Car. We will then define individual types of Car, which will inherit from the base class, Car. Let's look at the following code example to understand this better:

  1. Create a base class, Car. The class will have all the member attributes that are common across CarA and CarB:
public class Car
{
public DateTime manufacturingDate;
public string bodyType;
public float fuelCapacity;
public void ImplementBrake()
{
Console.WriteLine("Inside Base Class Implement Brake");
}
public void ImplementAccelerator()
{
Console.WriteLine("Inside Base Class Implement Accelerator");
}
}
  1. Create a class, CarA, which will inherit the base class. In C#, we use the: syntax to define inheritance:
public class CarA : Car
{
public CarA()
{
this.bodyType = string.Empty;
this.manufacturingDate = DateTime.MinValue;
this.fuelCapacity = 0.0F;
}
public CarA(DateTime manufacturingDate, string bodyType, float fuelCapacity)
{
this.bodyType = bodyType;
this.manufacturingDate = manufacturingDate;
this.fuelCapacity = fuelCapacity;
Console.WriteLine("Inside Car A Constructor");
}
public void FoldableSeat()
{
Console.WriteLine("Inside Car A Foldable Seat");
}
}

As indicated earlier, the attributes declared inside the parent class are automatically available in the derived class.

Please note that the attributes from the base class that will be available in the child class depend upon the access modifiers used against the corresponding attributes in the base class.

In our example, we have used public access modified in the base class. If it had been private or protected internal, its accessibility would have differed in the child class.

Let's consider a scenario wherein, for some reason, we also need to declare an attribute by the same name, bodyType, in CarA. In C#, we can differentiate between the attributes present in the base class and in the derived class by using the base keyword. Refer to the following code for this:

public class CarA : Car
{
string bodyType;
public CarA()
{
this.bodyType = string.Empty;
base.bodyType = string.Empty;
this.manufacturingDate = DateTime.MinValue;
this.fuelCapacity = 0.0F;
}

If base is used, it refers to the attribute in the parent class and, if this is used, it refers to the attribute in the child class.

  1. Similarly, declare a class for CarB:
class CarB : Car
{
public CarB()
{
this.bodyType = string.Empty;
this.manufacturingDate = DateTime.MinValue;
this.fuelCapacity = 0.0F;
}
public CarB(DateTime manufacturingDate, string bodyType, float fuelCapacity)
{
this.bodyType = bodyType;
this.manufacturingDate = manufacturingDate;
this.fuelCapacity = fuelCapacity;
Console.WriteLine("Inside Car B Constructor");
}
public void RoofTopExtendable()
{
Console.WriteLine("Inside Car B Foldable Seat");
}
}

Please note that, in derived classes, we can also create member variables independent of the base classes. As indicated in the preceding screenshots, the CarA class has an implementation of FoldableSeat, which is not present in the base class.

Similarly, the CarB class has an implementation of RoofTopExtendable, which is not present in the base class.

  1. In the main method, declare the CarA and CarB objects and call the respective methods:
CarA carA = new CarA();
carA.ImplementAccelerator();
carA.ImplementBrake();
carA.FoldableSeat();

CarB carB = new CarB();
carB.ImplementAccelerator();
carB.ImplementBrake();
carB.RoofTopExtendable();
Console.ReadLine();

  1. Click on Build | Build Solution. Notice that there are no compile-time errors. Now click on Debug | Start Debugging. Notice that the following output comes up in the console window:

The following provides a brief analysis of each of the output line items:

  • The first method we call is ImplementAccelerator, which is present in the base class. As expected, it executes the method in the base class.
  • Similarly, the next method we call is ImplementBrake, which is also present in the base class. In this case also, the method in the base class is executed.
  • In the next call, we execute a method just present in CarA. In this case, the control executes the code present in that function.
  • The same thing applies to B as well.

Thus, using inheritance, we can promote a greater degree of code reuse, along with making the maintenance activity quite scalable.

Once we move on to Chapter 3, Understanding Object-Oriented Programming, we will cover more features in regard to inheritance, such as overriding sealed, abstract classes and so on. However, for now, we will go over how an interface helps us in C# code development.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.71.21