Inheritance in C#
In object-oriented programming, inheritance is another type of relationship between classes. Inheritance is a mechanism of reusing the functionalities of one class into another related class.
Inheritance is referred to as "is a" relationship. In the real world example, a customer is a person. In the same way, a student is a person and an employee is also a person. They all have some common things, for example, they all have a first name, middle name, and last name. So to translate this into object-oriented programming, we can create the Person class with first name, middle name, and last name properties and inherit the Customer, Student, and Employee classes from the Person class. That way we don't need to create the same properties in all classes and avoid the violation of the DRY (Do not Repeat Yourself) principle.
Note that the inheritance can only be used with related classes where they should have some common behaviors and perfectly substitutable. Follow the Liskov Substitution Principle in inheritance.
In C#, use the :
symbol to inherit a class from another class. For example, the following Employee
class inherits from the Person
class in C#.
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string GetFullName(){
return FirstName + " " + LastName;
}
}
class Employee : Person
{
public int EmployeeId { get; set; }
public string CompanyName { get; set; }
}
In the above example, the Person
class is called the base class or the parent class, and the Employee
class is called the derived class or the child class.
The Employee
class inherits from the Person
class and so it automatically acquires all the public members of the Person
class. It means even if the Employee
class does not include FirstName
, LastName
properties and GetFullName()
method, an object of the Employee
class will have all the properties and methods of the Person
class along with its own members.
Employee emp = new Employee();
emp.FirstName = "Steve";
emp.LastName = "Jobs";
emp.EmployeeId = 1;
emp.CompanyName = "Apple";
var fullname = emp.GetFullName(); //Steve Jobs
Note that C# does not allow a class to inherit multiple classes. A class can only achieve multiple inheritances through interfaces.
Role of Access Modifiers in Inheritance
Access modifiers play an important role in inheritance. Access modifiers of each member in the base class impact their accessibility in the derived class.
Public Members
The public members of the base class are accessible in the derived class and also become part of the derived class object.
class Person
{
public string FirstName { get; set; } // can be inherited
}
class Employee : Person
{
}
Employee emp = new Employee();
emp.FirstName = "Bill"; // valid
Private Members
The private members of the base class cannot be accessed directly from the derived class and cannot be part of the derived class object.
class Person
{
private string FirstName { get; set; } // cannot be inherited
}
class Employee : Person
{
}
Employee emp = new Employee();
emp.FirstName; // Compile-time error
Protected Members
The protected members of the base class can be accessible in the derived class but cannot be a part of the derived class object.
class Person
{
protected string FirstName { get; set; }
}
class Employee : Person
{
public int GetName()
{
return this.FirstName;// valid
}
}
Employee emp = new Employee();
emp.GetName();// valid
emp.FirstName; // Compile-time error.
Internal Members
Internal members are accessible in the derived class and are part of the derived class object.
class Person
{
internal string FirstName { get; set; }
}
class Employee : Person
{
}
Employee emp = new Employee();
emp.Name= "Steve";// valid
Constructors
Creating an object of the derived class will first call the constructor of the base class and then the derived class. If there are multiple levels of inheritance then the constructor of the first base class will be called and then the second base class and so on.
class Person
{
public Person()
{
Console.WriteLine("Person Constructor");
}
}
class Employee : Person
{
public Employee()
{
Console.WriteLine("Employee Constructor");
}
}
Employee emp = new Employee();
Employee Constructor
Use the base
keyword in the derived class to access the public members of the base class. For example, the following calls the base class's parameterized constructor using the :base()
.
class Person
{
public Person()
{
Console.WriteLine("Person Constructor");
}
public Person(string val)
{
Console.WriteLine(val);
}
}
class Employee : Person
{
public Employee() : base("Parameterized constructor of base class")
{
Console.WriteLine("Employee Constructor");
}
}
Employee emp = new Employee();
Employee Constructor
Object Initialization
You can create an instance of the derived class and assign it to a variable of the base class or derived class. The instance's properties and methods are depending on the type of variable it is assigned to. Here, a type can be a class or an interface, or an abstract class.
The following table list supported members based on a variable type and instance type.
Instance variable | Instance Type | Instance Members of |
---|---|---|
Base type | Base type | Base type |
Base type | Derived type | Base type |
Derived type | Derived type | Base and derived type |
The following program demonstrates supported members based on the variable type:
class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Employee : Person
{
public string CompanyName { get; set; }
public decimal Salary { get; set; }
}
public class Program
{
public static void Main()
{
Person per1 = new Person();
per1.Id = 1; //valid
per1.FirstName = "James"; //valid
per1.LastName = "Bond"; //valid
//per1.CompanyName; // not supported
//per1.Salary; // not supported
Person per2 = new Employee();
per2.Id = 2; //valid
per2.FirstName = "Bill"; //valid
per2.LastName = "Gates"; //valid
//per2.CompanyName; // not supported
//per2.Salary; // not supported
Employee emp = new Employee();
emp.Id = 1; //valid
emp.FirstName = "Steve";//valid
emp.LastName = "Jobs";//valid
emp.CompanyName = "XYZ"; //valid
emp.Salary = 10000; //valid
//invalid, can't assign base type to derived type
//Employee emp = new Person();
}
}
In the above example, the type of per2
is Person
, so it will only expose public properties of the Person
type even if an object type is the Employee
. However, the type of emp
is Employee
and so it exposes all the public properties of both classes. Note that the base type object cannot be assigned to the derived type variable.
Type Conversion
The base type converts to the base class implicitly whereas the derived type must be converted to the base class explicitly using the as
operator.
public static void Display(Employee emp){
Console.WriteLine($"Name: {emp.FirstName} {emp.LastName}");
}
public static void Main()
{
Person per = new Employee();
per.FirstName="Steve";
per.LastName="Jobs";
//Cannot convert from Person to Employee implicitly
Display(per);//error
Display(per as Employee);//valid, explicit conversion
Employee emp = new Employee();
emp.FirstName = "Abdul";
emp.LastName = "Kalam";
Display(emp);//valid
}
Company Name:
Employee Name: Abdul Kalam
Company Name:
Types of Inheritance
There are different types of inheritance supported in C# based on how the classes are inherited.
Single Inheritance
In a single inheritance, only one derived class inherits a single base class.
Multi-level Inheritance
In multi-level inheritance, a derived class inherits from a base class and then the same derived class becomes a base class for another derived class. Practically, there are no limits on the level of inheritance, but you should avoid it.
Hierarchical Inheritance
In hierarchical inheritance, multiple derived classes inherit from a single base class.
Hybrid Inheritance
Hybrid inheritance is a combination of multi-level and hierarchical inheritance.
Multiple Inheritance
In multiple inheritance, a class inherits from multiple interfaces. Note that C# does not support deriving multiple base classes. Use interfaces for multiple inheritance.
Important Points:
- In C#, three types can participate in inheritance: Class, Struct, and Interface.
- A class can inherit a single class only. It cannot inherit from multiple classes.
- A class cannot inherit from a struct.
- A class can inherit (implement) one or more interfaces.
- A Struct can inherit from one or more interfaces. However, it cannot inherit from another struct or class.
- An interface can inherit from one or more interfaces but cannot inherit from a class or a struct.
- Constructors or destructors cannot be inherited.