Co to jest dziedziczenie wirtualne?

Dziedziczenie wirtualne to rodzaj dziedziczenia, w którym implementacja nadklasy jest niekompletna, a do pełnego zdefiniowania obiektu wymagana jest podklasa. Ten typ dziedziczenia może być używany w połączeniu z dziedziczeniem pojedynczym i wielokrotnym, ale najczęściej jest używany w dziedziczeniu wielokrotnym. Każda klasa, która dziedziczy z wirtualnej klasy bazowej, staje się bezpośrednią podklasą tej klasy bazowej. Wirtualna klasa bazowa może polegać na podklasie w celu zaimplementowania wszystkich jej metod, ale nie jest to wymagane.

C++ jest najbardziej znanym językiem komputerowym do korzystania z wirtualnego dziedziczenia. Do zadeklarowania wirtualnego dziedziczenia w C++ używa się słowa kluczowego „virtual”. Zarówno nadklasa, jak i podklasa muszą deklarować metody wirtualne ze słowem kluczowym „wirtualny”. To mówi kompilatorowi C++, że nadklasa jest niekompletna i musi uzyskać informacje z podklasy, aby ją ukończyć. Użycie podklasy do ukończenia nadklasy nie oznacza, że ​​podklasy nadpisują się nawzajem, jeśli mają tę samą klasę bazową, a zamiast tego kompilator C++ zajmuje się określeniem, które elementy pasują do każdego obiektu.

Ponieważ wirtualna klasa bazowa jest wymagana do wirtualnego dziedziczenia, globalne funkcje w C++ nie mogą być zadeklarowane jako wirtualne. Ten typ dziedziczenia może być używany tylko w przypadku przestrzegania zasad programowania obiektowego (OOP). Powodem tego jest to, że funkcje globalne nie są skojarzone z konkretną klasą, a więc są zwykle samodzielne. Bez nadklasy i podklasy dziedziczenie nie może się zdarzyć, więc funkcje globalne i dziedziczenie wirtualne wzajemnie się wykluczają. Funkcje globalne mogą teoretycznie być używane wewnątrz funkcji wirtualnych, ale nie zawsze działa to odwrotnie.

Dziedziczenie wirtualne służy do rozwiązywania wielu problemów programistycznych, a jednym z najbardziej użytecznych jest rozwiązywanie niejednoznaczności. W dziedziczeniu wielokrotnym można mieć klasę bazową A, która ma dwie podklasy, B i C, a następnie klasę D, która dziedziczy z obu klas B i C. Ten wzorzec jest powszechnie nazywany „diamentem śmierci”, ponieważ jeśli klasy A, Wszystkie B i C mają implementacje tej samej metody, nie jest możliwe, aby klasa D określiła, której implementacji powinna użyć. Dziedziczenie wirtualne rozwiązuje ten problem, ponieważ implementacja każdej klasy pozostaje odrębna, a zatem jednoznaczna. To rozróżnienie jest obsługiwane przez wyspecjalizowane obiekty wewnętrzne zwane tabelami wirtualnymi (vtables), które śledzą każdy typ obiektu, ale te tabele nie muszą być jawnie manipulowane przez programistę, ponieważ są wbudowane w język.