Na początek pytanie: czym różni się metoda wirtualna od implementacji metody z interfejsu?
Mogło by się zdawać, że są to bardzo podobne operacje. Dostarczamy definicję metody zadeklarowanej w innym typie. W interfejsie metoda nie jest wirtualna - przynajmniej nie domyślnie. Klasy dziedziczące po klasie, która implementuje interfejs nie mogą nadpisywać metod zaimplementowanych w klasie bazowej.
Tutaj jest jeden haczyk - można tak zaimplementować metody interfejsu aby istniała możliwość ich nadpisania w klasach potomnych.
Zobaczmy na prosty przykład:
Code:
Code:
Code:
Wywołanie funkcji w mainie:
Code:
Efekt który można przewidzieć:
Code:
Zdarza się jednak, że chcemy w potomnych klasach przedefiniować funkcję implementowaną z interfejsu w klasie bazowej. Mamy dwie możliwości. Jeżeli nie mamy dostępu do klasy bazowej możemy zaimplementować interfejs w klasie dziedziczącej:
Code:
Wynik:
Code:
Jednak wersja bazowa jest nadal dostępna:
Code:
Wynik:
Code:
Jedną z metod naprawienia tego problemu jest zadeklarowanie metody Voice w klasie bazowej jako wirtualnej, a następnie w klasie dziedziczącej nadpisanie tej metody:
Code:
Możemy iść dalej i klasę bazową zadeklarować jako abstrakcyjną (tak można zaimplementować interfejs bez implementacji jego metody):
Code:
Klasa dziedzicząca może następnie zapobiec przeładowywaniu metody Voice w kolejnych potomnych klasach:
Code:
Ostatni aspekt. Jeżeli dziedziczymy po klasie bazowej, która implementuje interfejs, dziedzicząca także ma zadeklarowaną implementację w sygnaturze to w dziedziczącej nie musimy implementować metody:
Code:
Interfejsy pozwalają na abstrakcyjną, wirtualną i zamkniętą implementację. Daje to dużą elastyczność w przypadku tworzenia hierarchii klas.
Brak komentarzy:
Prześlij komentarz