C# Inheritance
Inheritance in C# is an object-oriented programming feature that allows one class to reuse and extend members defined by another class. It is useful when two types have a clear is-a relationship, such as a sports car being a specialized type of car.
The class whose members are inherited is called the base class or parent class. The class that inherits those members is called the derived class or child class.
A derived class can access eligible members of its base class, add new members, hide inherited members, or override virtual and abstract members. Private members remain part of the base-class implementation but cannot be accessed directly from the derived class.
C# Inheritance Syntax
Place a colon after the derived class name, followed by the name of the base class.
class BaseClass
{
// Base-class members
}
class DerivedClass : BaseClass
{
// Additional derived-class members
}
C# supports single inheritance for classes, which means a class can directly inherit from only one base class. A class can still implement multiple interfaces.
Example 1 – Inheriting Members from a C# Base Class
This example demonstrates how a derived class can use members declared in a base class.
Consider an application that models a production line for cars. We define a base class named Car and a derived class named SportsCar. A sports car can be treated as a specialized type of car.
The Car class contains fields and methods that are common to cars. The SportsCar class inherits those members and declares additional members of its own.
Program.cs
using System;
namespace CSharpExamples {
class Car {
public int chasis_number;
public string name;
public void addWheels(){
Console.WriteLine("4 wheels added.");
}
public void addSeats(){
Console.WriteLine("4 seats added.");
}
}
class SportsCar: Car {
public string name;
public SportsCar(int chasis_number, string name){
this.name = name;
this.chasis_number = chasis_number;
}
public void addSeats(){
Console.WriteLine("2 seats added.");
}
public void printDetails(){
Console.WriteLine("\nCar Details\n------------");
Console.WriteLine("Chasis Number : " + this.chasis_number);
Console.WriteLine("Car Name : " + this.name);
}
}
class Program {
static void Main(string[] args) {
SportsCar car1 = new SportsCar(254, "McLaren 570S");
car1.addSeats();
car1.addWheels();
car1.printDetails();
}
}
}
Base class: Car declares the fields chasis_number and name, along with the methods addWheels() and addSeats().
Derived class: SportsCar inherits from Car. It can therefore use the inherited chasis_number field and addWheels() method. It also declares a constructor and a new method named printDetails().
The declarations of name and addSeats() in SportsCar do not perform polymorphic overriding because the corresponding base members are not declared with virtual. Instead, the derived members hide the inherited members. The compiler warnings shown later identify this behavior.
Output
2 seats added.
4 wheels added.
Car Details
------------
Chasis Number : 254
Car Name : McLaren 570S
Example 2 – Field and Method Hiding in C# Inheritance
A base-class method accesses the members declared by its own class. It does not automatically use a same-named field declared later in a derived class.
In the following program, both Car and SportsCar declare a field named name. These are two separate fields. The constructor assigns a value to SportsCar.name, while Car.printDetails() reads Car.name.
Because Car.name is never assigned, its default value is null. Writing a null string to the console produces no text after Car Name :.
Program.cs
using System;
namespace CSharpExamples {
class Car {
public int chasis_number;
public string name;
public void addWheels(){
Console.WriteLine("4 wheels added.");
}
public void addSeats(){
Console.WriteLine("4 seats added.");
}
public void printDetails(){
Console.WriteLine("\nCar Details\n------------");
Console.WriteLine("Chasis Number : " + this.chasis_number);
Console.WriteLine("Car Name : " + this.name);
}
}
class SportsCar: Car {
public string name;
public SportsCar(int chasis_number, string name){
this.name = name;
this.chasis_number = chasis_number;
}
public void addSeats(){
Console.WriteLine("2 seats added.");
}
}
class Program {
static void Main(string[] args) {
SportsCar car1 = new SportsCar(254, "McLaren 570S");
car1.addSeats();
car1.addWheels();
car1.printDetails();
}
}
}
Output
2 seats added.
4 wheels added.
Car Details
------------
Chasis Number : 254
Car Name :
You might observe the following warnings before the actual output shown above.
Program.cs(21,23): warning CS0108: 'SportsCar.name' hides inherited member 'Car.name'. Use the new keyword if hiding was intended. [D:\workspace\csharp\HelloWorld\HelloWorld.csproj]
Program.cs(27,21): warning CS0108: 'SportsCar.addSeats()' hides inherited member 'Car.addSeats()'. Use the new keyword if hiding was intended. [D:\workspace\csharp\HelloWorld\HelloWorld.csproj]
Program.cs(6,23): warning CS0649: Field 'Car.name' is never assigned to, and will always have its default value null [D:\workspace\csharp\HelloWorld\HelloWorld.csproj]
Warning CS0108 means that a derived member hides an inherited member with the same name. You can use the new keyword to state that hiding is intentional, but overriding is usually more appropriate when runtime polymorphism is required.
Overriding C# Methods with virtual and override
To override a method, declare the base-class method with virtual and declare the derived implementation with override. The method selected at runtime then depends on the object’s actual type, even when the object is referenced through a base-class variable.
using System;
class Car
{
public virtual void AddSeats()
{
Console.WriteLine("4 seats added.");
}
}
class SportsCar : Car
{
public override void AddSeats()
{
Console.WriteLine("2 seats added.");
}
}
class Program
{
static void Main()
{
Car car = new SportsCar();
car.AddSeats();
}
}
Output
2 seats added.
Use override when a derived class must provide a specialized implementation of an inherited operation. Use new only when member hiding is intentional and polymorphic dispatch is not required.
Calling a C# Base-Class Constructor
A derived-class constructor can call a base-class constructor by using the base keyword. This lets the base class initialize the state that it owns.
class Car
{
public int ChassisNumber { get; }
public Car(int chassisNumber)
{
ChassisNumber = chassisNumber;
}
}
class SportsCar : Car
{
public string Name { get; }
public SportsCar(int chassisNumber, string name)
: base(chassisNumber)
{
Name = name;
}
}
If the base class has a parameterless constructor, the compiler can insert an implicit call to base(). If the base class exposes only parameterized constructors, the derived constructor must explicitly call one of them.
Access Modifiers for Inherited C# Members
public: accessible from the derived class and other code that can access the containing type.protected: accessible within the base class and its derived classes.private: accessible only within the class that declares the member.internal: accessible within the same assembly.protected internal: accessible from the same assembly or from a derived class in another assembly.private protected: accessible from derived classes only when they are in the same assembly.
Base-class fields are commonly kept private and exposed through properties or protected methods. This prevents derived classes from depending directly on internal implementation details.
Single, Multilevel, and Hierarchical Inheritance in C#
C# class hierarchies can take several forms:
- Single inheritance: one class directly inherits from one base class, such as
SportsCar : Car. - Multilevel inheritance: a class inherits from a derived class, such as
ElectricSportsCar : SportsCar. - Hierarchical inheritance: multiple classes inherit from the same base class, such as
SportsCar : CarandFamilyCar : Car.
C# does not allow a class to inherit from multiple classes. When a type needs capabilities from several contracts, implement multiple interfaces instead.
When to Use Inheritance in C#
Use inheritance when the derived type is genuinely a specialized form of the base type and can safely be used wherever the base type is expected. Shared code alone is not always enough to justify an inheritance relationship.
- Use inheritance for stable is-a relationships.
- Use composition when one object merely contains or uses another object.
- Keep base classes focused so that derived classes do not inherit unrelated behavior.
- Prefer properties over public fields for data that must be validated or protected.
- Use
virtualselectively because derived classes become dependent on the base-class contract.
C# Inheritance Summary
In this C# Tutorial, we learned how a derived class inherits accessible members from a base class, how field and method hiding differ from overriding, how to use virtual, override, and base, and how access modifiers affect inherited members.
TutorialKart.com