Inheritance
What Is Inheritance
Inheritance is a core mechanism of object-oriented programming that allows one class to reuse the members of another class and extend it with new functionality. C# only supports single inheritance, meaning a class can have only one direct base class.
Inheritance Syntax
Use class DerivedClass : BaseClass to declare an inheritance relationship. The derived class automatically acquires all non-private members of the base class.
Example
class Animal
{
public string Name { get; set; }
public void Eat()
{
Console.WriteLine($"{Name} is eating.");
}
}
class Dog : Animal
{
public void Bark()
{
Console.WriteLine($"{Name}: Woof!");
}
}
class Program
{
static void Main()
{
Dog dog = new Dog { Name = "Buddy" };
dog.Eat();
dog.Bark();
}
}
Buddy is eating.
Buddy: Woof!
The base Keyword
base is used to call the base class's constructors and member methods. In a constructor, pass arguments to the parent constructor via base(args); in a method, call the parent implementation via base.Method().
Example
class Person
{
public string Name { get; }
public Person(string name)
{
Name = name;
}
public virtual void Introduce()
{
Console.WriteLine($"I am {Name}.");
}
}
class Student : Person
{
public int Grade { get; }
public Student(string name, int grade) : base(name)
{
Grade = grade;
}
public override void Introduce()
{
base.Introduce();
Console.WriteLine($"I am in grade {Grade}.");
}
}
class Program
{
static void Main()
{
Student s = new Student("Alice", 3);
s.Introduce();
}
}
I am Alice.
I am in grade 3.
Method Overriding with virtual/override
The base class marks overridable methods with virtual, and the derived class provides a new implementation using override. This is the foundation of polymorphism.
Example
class Shape
{
public virtual double Area()
{
return 0;
}
}
class Circle : Shape
{
public double Radius { get; set; }
public Circle(double radius)
{
Radius = radius;
}
public override double Area()
{
return Math.PI * Radius * Radius;
}
}
class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public Rectangle(double w, double h)
{
Width = w;
Height = h;
}
public override double Area()
{
return Width * Height;
}
}
class Program
{
static void Main()
{
Shape[] shapes = { new Circle(2), new Rectangle(3, 4) };
foreach (Shape s in shapes)
{
Console.WriteLine($"Area: {s.Area():F2}");
}
}
}
Area: 12.57
Area: 12.00
Method Hiding with new
If a derived class defines a method with the same name as one in the base class without using override, the compiler issues a warning. The new keyword explicitly hides the base class method, indicating that this is an independent method rather than an override.
Example
class Base
{
public void Greet()
{
Console.WriteLine("Hello from Base");
}
}
class Derived : Base
{
public new void Greet()
{
Console.WriteLine("Hello from Derived");
}
}
class Program
{
static void Main()
{
Derived d = new Derived();
d.Greet();
Base b = d;
b.Greet();
}
}
Hello from Derived
Hello from Base
new hiding and override overriding: when called through a base class reference, new executes the base class version, while override executes the derived class version.
sealed: Preventing Inheritance
Applying sealed to a class means it cannot be inherited; applying it to a method means the method cannot be further overridden.
Example
class Config
{
public virtual void Load()
{
Console.WriteLine("Loading config...");
}
}
class JsonConfig : Config
{
public sealed override void Load()
{
Console.WriteLine("Loading JSON config...");
}
}
sealed class FinalClass
{
public void DoWork() { }
}
class Program
{
static void Main()
{
JsonConfig cfg = new JsonConfig();
cfg.Load();
}
}
Loading JSON config...
JsonConfig.Load is marked sealed, any class deriving from JsonConfig can no longer override Load. Once FinalClass is marked sealed, no class can inherit from it at all.
Constructor Chaining in Inheritance
When a derived class object is created, the base class constructor always executes before the derived class constructor. If the base class has no parameterless constructor, the derived class must explicitly call base(args).
Example
class Vehicle
{
public string Type { get; }
public Vehicle(string type)
{
Type = type;
Console.WriteLine($"Vehicle({type}) constructed");
}
}
class Car : Vehicle
{
public string Brand { get; }
public Car(string brand) : base("Car")
{
Brand = brand;
Console.WriteLine($"Car({brand}) constructed");
}
}
class Program
{
static void Main()
{
Car car = new Car("Toyota");
}
}
Vehicle(Car) constructed
Car(Toyota) constructed
The object Root Class
All types in C# inherit from System.Object (alias object). It provides foundational methods such as ToString(), Equals(), GetHashCode(), and GetType().
Example
class Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public override string ToString()
{
return $"({X}, {Y})";
}
public override bool Equals(object obj)
{
if (obj is Point other)
{
return X == other.X && Y == other.Y;
}
return false;
}
public override int GetHashCode()
{
return HashCode.Combine(X, Y);
}
}
class Program
{
static void Main()
{
Point p1 = new Point(1, 2);
Point p2 = new Point(1, 2);
Console.WriteLine(p1.ToString());
Console.WriteLine(p1.Equals(p2));
Console.WriteLine(p1.GetType().Name);
}
}
(1, 2)
True
Point
The is and as Operators
is performs a type check and returns a bool; as performs a safe type conversion, returning null on failure instead of throwing an exception.
Example
class Animal { }
class Cat : Animal
{
public void Meow() { Console.WriteLine("Meow!"); }
}
class Dog : Animal
{
public void Bark() { Console.WriteLine("Woof!"); }
}
class Program
{
static void Main()
{
Animal a = new Cat();
if (a is Cat)
{
Console.WriteLine("a is a Cat");
}
if (a is Dog)
{
Console.WriteLine("a is a Dog");
}
else
{
Console.WriteLine("a is not a Dog");
}
Cat c = a as Cat;
if (c != null)
{
c.Meow();
}
Dog d = a as Dog;
Console.WriteLine($"as Dog result is null: {d == null}");
}
}
a is a Cat
a is not a Dog
Meow!
as Dog result is null: True
is pattern matching: if (a is Cat cat) can check the type and declare a variable at the same time.
❓ FAQ
new to declare this explicitly.📖 Summary
- Inheritance uses the
class Derived : Basesyntax; C# only supports single inheritance - The
basekeyword calls the parent class constructor and member methods virtual/overrideimplements method overriding, which is the foundation of polymorphism- The
newkeyword explicitly hides a base class method, behaving differently from overriding sealedon a class prevents inheritance; on a method it prevents further overriding- Constructors execute from base class to derived class in order
- All types inherit from
object, and you can overrideToString,Equals, andGetHashCode isperforms type checking;asperforms safe conversion
📝 Exercises
- Define an
Employeebase class (withNameandSalaryproperties), derive aManagerclass (with an additionalLevelproperty), and usebasein theManagerconstructor to call the parent constructor. - Define a
virtual void Work()method inEmployee, override it withoverrideinManager, and callbase.Work()inside the overridden method. - Create an
Employee[]array containing bothEmployeeandManagerobjects, use theisoperator to determine the type, and output different information accordingly. - Override the
ToString()method inManagerto return a string containingName,Salary, andLevel. - Declare a
sealedclassPayCalculator, then try to write a class that inherits from it and observe the compilation error.



