Moștenire: virtual, override și base în C# (.NET)

O clasă derivată preia membrii clasei de bază (class B : A); metodele virtual pot fi înlocuite cu override, iar base apelează varianta de bază.

Sintaxă C#
class Angajat : Persoana { public override string Descriere() => base.Descriere() + " ..."; }

Ce face Moștenire: virtual, override și base

În C# o clasă moștenește dintr-o singură clasă de bază, scrisă după două puncte: class Student : Persoana. Clasa derivată primește câmpurile, proprietățile și metodele accesibile ale bazei și poate adăuga altele. Un obiect Student poate fi folosit oriunde se așteaptă o Persoana.

O metodă poate fi înlocuită în clasa derivată doar dacă baza o marchează virtual (sau abstract); derivata scrie override. Apelul se decide la rulare, după tipul real al obiectului (polimorfism). Cu base.Metoda() derivata poate refolosi implementarea bazei, iar : base(...) la constructor trimite argumente constructorului bazei.

Fără override, o metodă cu același nume ascunde metoda bazei (cuvântul new, cu avertismentul CS0108 dacă lipsește), iar apelul printr-o variabilă de tipul bazei ajunge la metoda bazei. De obicei asta nu e ce vrei.

Exemple

Exemplul 1: Polimorfism cu virtual și override

List<Angajat> echipa =
[
    new Angajat("Ana", 6000),
    new Manager("Mihai", 9000, 2000),
];

foreach (Angajat a in echipa)
    Console.WriteLine($"{a.Nume}: {a.Salariu()} lei");

class Angajat(string nume, int baza)
{
    public string Nume { get; } = nume;
    protected int Baza { get; } = baza;

    public virtual int Salariu() => Baza;
}

class Manager(string nume, int baza, int bonus) : Angajat(nume, baza)
{
    public override int Salariu() => base.Salariu() + bonus;
}

Rezultat

Ana: 6000 lei
Mihai: 11000 lei

Exemplul 2: override față de new (ascundere)

Prin variabila de tip Animal, doar metoda cu override ajunge la clasa derivată.

Animal a1 = new Caine();
Animal a2 = new Pisica();
Console.WriteLine(a1.Sunet());
Console.WriteLine(a2.Sunet());
Console.WriteLine(new Pisica().Sunet());

class Animal
{
    public virtual string Sunet() => "...";
}

class Caine : Animal
{
    public override string Sunet() => "Ham";
}

class Pisica : Animal
{
    public new string Sunet() => "Miau";
}

Rezultat

Ham
...
Miau

Greșeli frecvente

  • Uitarea lui virtual în bază: override dă eroarea CS0506, iar fără el metoda doar ascunde baza.
  • Moștenirea multiplă de clase nu există în C#: class C : A, B merge doar dacă B este interfață.
  • Moștenirea folosită doar ca să refolosești cod duce la ierarhii fragile. Când relația nu este „este un/o”, preferă compunerea (un câmp de tipul celeilalte clase) sau o interfață.

Comenzi înrudite

  • abstract (clase și metode abstracte): O clasă abstract nu poate fi instanțiată direct; metodele abstract nu au corp și trebuie implementate de fiecare clasă derivată.
  • sealed: Interzice moștenirea unei clase sau suprascrierea mai departe a unei metode override.
  • Constructori (this, supraîncărcare, static): Constructorul inițializează un obiect creat cu new; poate avea variante, poate apela altă variantă cu : this(…) și există și constructor static.