Przesłanianie kontra nadpisywanie

2008-02-14 19:08

Jednym ze swego rodzaju kruczków programowania obiektowego jest różnica między przesłanianiem (hide) a nadpisywaniem (override) metod w klasach pochodnych. Niby nic w tym trudnego, dopóki nie uświadomimy sobie, że metody wirtualne – w przeciwieństwie do zwykłych – mogą podlegać obu tym procesom i że w ich przypadku różnią się one w dość istotny sposób.

Jeśli mianowicie mamy jakąś metodę wirtualną w klasie bazowej, to w klasie pochodnej teoretycznie możemy ją zarówno nadpisać, jak i przesłonić. Gdy zdecydujemy się na to pierwsze wyjście, wówczas nasz obiekt staje się polimorficzny. Posługując się wskaźnikiem lub referencją do obiektu klasy bazowej tak naprawdę możemy operować na obiekcie klasy pochodnej, a wywołując metodę wirtualną nie wiemy, która jej wersja będzie użyta. Wiemy jedynie, że będzie to ta “właściwa” (z klasy, do której należy nasz obiekt). No cóż, to podstawa OOP-u, jakkolwiekby na to nie patrzeć :)

  1. // klasa bazowa
  2. class CBase { public: virtual void Foo() { /* ... */ } };
  3.  
  4. // klasa pochodna
  5. class CDerived : public CFoo
  6. {
  7.    public:
  8.       // nadpisana metoda
  9.       void Foo()   { /* ... */ }
  10. };

Nie zawsze jednak musi tak być. Jeżeli metodę wirtualną się przesłoni, wtedy nic takiego nie zadziała i zostanie wywołana wersja z klasy bazowej. Typ obiektu nie zostanie bowiem rozpoznany w trakcie działania programu, a całe wywołanie będzie zapisane “na sztywno” w wynikowym kodzie. W gruncie rzeczy będzie tak samo, jakbyśmy przesłoni dowolną inną (niewirtualną) metodę.
O ile oczywiście możemy, bowiem w C++ metody wirtualnej przesłonić się po prostu nie da. Nadpisywanie jest po prostu wykonywane automatycznie i nie można z niego zrezygnować. W innych językach (jak w Delphi i C#) wymaga ono słowa kluczowego override. Tam też metody wirtualne można przesłaniać, stosując modyfikatory – odpowiednio reintroduce i new.

Żeby było zabawniej, przesłanianie i nadpisywanie może występować dla tej samej metody w tej samej hierarchii dziedziczenia. Metoda wirtualna zdefiniowana w klasie A może być na przykład nadpisywana w kolejnych klasach pochodnych A1, A2, A3, itd. I nagle w klasie B zostanie ona przesłonięta. Ba, ta przesłonięta wersja sama może być wirtualna i nadpisywana w dalszych klasach pochodnych: B1, B2, B3, …
Nie spotyka się tego często, jako że podobne wielopiętrowe drzewa dziedziczenia są rzadkie (i takie być powinny). Warto jednak o tym wiedzieć, bo nigdy nie wiadomo, kiedy podobny kruczek przybierze w naszym kodzie postać wielkiego kruka i zacznie nas dziobać zagadkowymi błędami ;]

Tags: , ,
Author: Xion, posted under Programming »


One comment for post “Przesłanianie kontra nadpisywanie”.
Comments are disabled.
 


© 2019 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.