In C#, a class hierarchy can be defined using inheritance, which allows a derived class (Car
) to inherit the behavior and data of its parent class (Vehicle
). If no parent is specified, the class inherits from the object
class.
Parent classes can provide functionality to derived classes in three ways:
virtual
method, which is like a regular method but one that derived classes can change.abstract
method, which is a method without an implementation that derived classes must implement. A class with abstract
methods must be marked as abstract
too. Abstract classes cannot be instantiated.The protected
access modifier allows a parent class member to be accessed in a derived class, but blocks access from other classes. Derived classes thus can access public
and protected
parent class members, but not private
parent class members.
Derived classes can access parent class members through the base
keyword.
// Inherits from the 'object' class
abstract class Vehicle
{
// Can be overridden
public virtual void Drive()
{
}
// Must be overridden
protected abstract int Speed();
}
// Cannot be inherited from
sealed class Car : Vehicle
{
public override void Drive()
{
// Override virtual method
// Call parent implementation
base.Drive();
}
protected override int Speed()
{
// Implement abstract method
}
}
The constructor of a derived class will automatically call its parent's constructor before executing its own constructor's logic. Arguments can be passed to a parent class' constructor using the base
keyword. As abstract classes cannot be instantiated, their constructors can be made protected
.
abstract class Vehicle
{
protected Vehicle(int wheels)
{
Console.WriteLine("Called first");
}
}
class Car : Vehicle
{
public Car() : base(4)
{
Console.WriteLine("Called second");
}
}
Where more than one class is derived from a base class the two (or more) sub-classes will often implement different versions of a base class method. This is a very important principle called polymorphism. For instance in a variation on the above example we show how code using Vehicle
can change its behavior depending on what type of vehicle has been instantiated.
abstract class Vehicle
{
public abstract string GetDescription();
}
class Car : Vehicle
{
public Car()
{
}
public override string GetDescription()
{
return "Runabout";
}
}
class Rig : Vehicle
{
public Rig()
{
}
public override string GetDescription()
{
return "Big Rig";
}
}
Vehicle v1 = new Car();
Vehicle v2 = new Rig();
v1.GetDescription();
// => Runabout
v2.GetDescription();
// => Big Rig
To prevent a class being inherited, add the sealed
modifier.
Some practitioners try to avoid inheriting from concrete classes (as discussed in this SO question) and the sealed modifier supports this approach. On the other hand many C# developers consider them a hindrance to maintenance as discussed in some of the comments on this question. The advice is to use the sealed modifier sparingly until you have gained confidence in their use for your requirements.
The following article describes new
as an alternative to the override
modifier. This is occasionally useful, perhaps with convoluted class hierarchies and/or some sort of clash of libraries.