C++ Metody wirtulalne

Metody wirtulalne - jest przygotowana na zastąpienie siebie przez nową wersję zdefiniowaną w klasie pochodnej => w klasie bazowej

Deklaracja metody wirtualnej

#include<iostream>
class CAnimal
{
// (pomijamy pozostałe składowe klasy)
public:
  virtual void Oddychaj() {std::cout <<"Oddycham ..."<< std::endl;}
};


///////////

class CFish: public CAnimal
{
public:
  void Oddychaj() //redefinicja metody wirtualnej
    {std::cout << "Odycham skrzelami .." <<std:endl;}
  void Płyn();
};

////////////

nazwa_klasy_bazowej :: nazwa_metody([parametry]);
//Wywołanie metody
(można zamiast nazwy_klasy_nazwy mozliwe jest użycie słowa kluczowego _super)

CAnimal * pZwierzak = new CMammal;
pZwierzak -> Oddychaj();
delete pZwierzak;

-wskaźnik, pZwierzak do obiektu klasy CAnimal a właściwie na tą klasą
-cMammal nowy obiekt klasy cMammal
-klasa cMammal dziedziczy od klasy cAnimal także każdy obiekt należący do tej pierwszej jest jednocześnie tez obiektem  tej drugiej

=> Kiedy jest "niewirtualność" jest to funkcja zwykła . W takich wypadkach decyzja, która metoda jest rzeczywiście wywołana, zostaje podjęta już na etapie kompilacji programu.Nazywamy ją wtedy wczesnym wiązaniem (early binding) funkcji. Do jej podjęcia są zatem jedynie te informacje, które są znane w momencie kompilacji programu. U nas jest to typ wskźnika pZwierzak .czyli cAnimal. Nie jest to przecież mozliwe do ustalenia, na jaki obiekt będzie on faktycznie wskazywał - owszem, moze on należać do klasy cAnimal, jednak równie dobrze do jej pochodnej, na przykład cMammal. Wiedza ta nie jest jednak dostępna podczas kompilacji, dlatego tutaj zostaje asekuracyjne wykorzystany jedynie znany typ cAnimal::Odychaj()!


Gdy będzie to funkcja wirtualna => virtual

Kompilator wstrzyma się z decyzją co do faktycznie przywoływanej metody. Jej podjęcie nastąpi dopiero w stosownej chwili podczas działania gotowej aplikacji; nazywamy to późnym wiązaniem (late binding) funkcji. W tym momencie będzie oczywiście wiadome, jaki obiekt naprawdę kryje się za naszym wskaźnikiem pZwierzak i to jego wersja metody zostanie wywołana. Uzyskamy zatem skutek, o jaki nam chodziło, czyli wywołanie funkcji cMammal::Oddychaj().


Wirtualny destruktor
- nie ma sensu virtual dla konstruktorów, ponieważ one i tak mają cechy wirtualności.
-użycie virtual do destruktorów jest prawie zawsze konieczne i zalecane

-delete nie jest wystarczający do zwolnienia pamięci jeśli nie jest użyty modyfikator virtual, ponieważ. Zwolniona jest tylko pamięć destruktorem klasy cAnimal a nie obie klasy by tego uniknąć należy destruktor klasy bazowej cAnimal uczynic wirtualnym:

class CAnimal
{
public:
  virtual ~cAnimal() {delete m_pSerca;}
};


Zawsze umieszczaj wirtualnych destruktor w klasie bazowej.

Metody nazywane czysto wirtualnymi (pure virtual, metody abstrakcyjne) nie posiadają żadnej implementacji i są przeznaczone wyłącznie do przedefiniowania w klasach pochodnych.


class cAnimal
{
public:
  virtual void Oddychaj() = 0;
};


Klasa abstrakcyjna - zawiera przynajmniej jedną czysto wirtualną metodę i z jej powodu nie jest przeznaczona do instancjowania (tworzenie z niej obiektów), a jedynie do wyprowadzania zeń klas pochodnych.

IAnimal * pZwierzę = new CBird; //IAnimal - klasa abstrakcyjna
pZwierzę -> Oddychaj ();
delete pZwierzę;

Komentarze

Popularne posty z tego bloga

Kubernetes

Helm

Ansible Tower / AWX