4.1.2.3 - Inheritance, polymorphism and object relationships (C#)
Learn how derived classes vary inherited behaviour, how polymorphism selects that behaviour, and how UML distinguishes inheritance from whole-part object relationships.
This C# route is incomplete: runnable support pending. The native examples and written code tasks have no Run.
Inheritance and overriding
Inheritance defines a specialised class from a more general base class. It represents an “is a” relationship: a Dog is an Animal. The derived class reuses the base's accessible members and adds or varies behaviour. C# classes have a single direct base class.
class Animal
{
private string name;
public Animal(string name) { this.name = name; }
protected string GetName() { return name; }
public virtual string Speak() { return name + " makes a sound"; }
}
class Dog : Animal
{
public Dog(string name) : base(name) { }
public override string Speak() { return GetName() + " barks"; }
}
The colon names the base class. base(name) calls its constructor to initialise the private base field. Dog cannot directly access name, but it can use the protected GetName method. The base Speak is virtual, so the derived method can override its implementation with the same compatible interface. The inherited method is not merely copied and edited in every class; the general behaviour stays in the base and only the variation is replaced.
The abstract method example from the previous lesson has the same overriding mechanism, but no base method body. A concrete subclass must implement the abstract operation. Inheritance can provide reuse and a common abstraction, but a misleading “is a” relationship or deep dependency chain makes changes harder: reuse alone is not enough reason to choose it.
Polymorphism
Polymorphism allows code written for a general type to work with different specialised objects. With virtual/abstract instance methods, the object's actual runtime type determines which override is called, even when the variable's declared type is the base class.
Animal[] animals = { new Animal("Bo"), new Dog("Pip") };
foreach (Animal animal in animals)
{
Console.WriteLine(animal.Speak());
}
The array and loop variable use Animal, but the second object is a Dog. The output is Bo makes a sound followed by Pip barks. The loop calls the same interface; it does not need a growing chain of type tests to decide how every animal speaks. Adding another correctly derived class can extend behaviour while preserving the loop.
Do not confuse overriding with declaring a different overload. An overload has a different parameter list and is selected using the call's arguments. A non-virtual method hidden with new does not give the same runtime override behaviour. For the taught polymorphic contract, the base is virtual or abstract and the derived method uses override.
Continue this lesson.
You’re previewing NovaLearn without an account. Create a free account to read the rest.
Create free account