C++ Dziedziczenie

Dziedziczenie (inheritance) to tworzenie nowej klasy ana podstawie jednej lub kilku istniejących klas bazowych

klasa bazowa

klasa pochodna - posiadają pewne elementy wpsólne części te są dziedziczone z klas bazowych, gdyż tam właśnie zostały zdefiniowane. Ich zbiór może jednak zostać poszerzona o pola i metody specyficzne dla klas pochodnych.
Będą one wspólistnieć z "dorobkiem" pochodzących z klas bazowych , ale moga oferować dodatkową funkcjonalność.

class nazwa_klasy
{
[private:]
    [deklaracje_prywatne]
[protected:]
    [deklaracje_chronione]
[public:]
    [deklaracje_publiczne]
};


Znaczenie etykiet, specyfikatorów:

a)private

-poprzedza deklarację składowych, które mają być dostępne jedynie dla metod definiowanej klasy
-tzn. nie można się do nich dostać, używając obiektu lub wskaźnika na niego oraz operatorów wyłuskania . lub ->
-ta wyłączność oznacza, że prywatne składowe nie są dziedziczone i nie ma do nich dostepu w klasach pochodnych, gdyż nie wchodzą w ich skład.

b)protected

-też nie pozwala, by użytkonicy obiektów naszej klasy "grzebali" w opatrzonych nimi polach i metodach. Jak sama nazwa wskazuje, są chronione przed dostępem z zewnątrz
-w przeciwieństwie do deklaracji private, składowe zaznaczone przez protectedsą dziedziczone , występują w klasach pochodnych, będąc dostępnymi dla ich własnych metod.



c)public

-pozwala na odziedziczenie swoich składowych, ale także na udostępnienie ich szerokiej rzeszy obiektów poprzez operatory wyłuskania.


Przykład:

klasa bazowa: 

class CRectangle
{
private:
  //wymiary prostokąta
  float m_fSzerokość, m_fWysokość;
protected:
  //pozycja na ekranie
  float m_fX, m_fY;
public:
  //konstruktor
  CRectangle() {m_fX = m_fY =0.0;m_fSzerokość=m_fWysokość=10.0;}
  //metody
  float Pole() const { return m_fSzerokość * m_fWysokość;}
  float Obwód() const { return 2*( m_fSzerokość + m_fWysokość);}
};

klasa podstawowa:

class CSquare: public CRectangle // dziedziczenie z CRectangle
{
private:
  //zamiast szerokości i wysokości mamy tylko długość boku
  float m_fDługośćBoku
  //pola m_fX, m_fY są dziedziczone z klasy bazowej, więc nie ma potrzeby ich powtórnego         //deklarowanie
public:
  //konstruktor
  CSquare {m_fDlugoscBoku = 10.0;}

  //nowe metody
  float Pole() const { return m_fDlugoscBoku * m_fDlugoscBoku;}
  float Obwód() const { return 4* m_fDlugoscBoku;}
};



Przed zdefiniowanej klasy pochodnej dopiero po zdefiniowaniu klasy bazowej.


Klasa pochodna

class nazwa_klasy[:[specyfikatory] [nazwa_klasy_bazowej][,..]]
{
deklaracje_składowych
};



Nie użycie specyfikatora klasy bazowej jest równoważne z użyciem specyfikatora private (a najczęściej używany specyfikator klas bazowych to public).


Dziedziczenie pojedyncze (jednokrotne) (single inheretance) - gdy mamy do czynienia z jedną klasą bazową

Dziedziczenie wielokrotnym (ang. multiple inheritance) z kilku klas bazowych powstaje jedna klasa pochodna.

"Nieprzechodne" składniki klas (z bazowej do pochodnej):
-to oznaczone private
-konstruktory - zadaniem konstruktora jest zazwyczaj inicjalizacja półklas na ich początkowe wartości, stworzenie wewnętrznych obiektów czy też alokacja dodatkowej pamięci. Czynności te prawie zawsze wymagają zatem dostępu do prywatnych pół klas. Jeżeli więc konstruktor z klasy bazowej został by "wrzucony" do klasy pochodnej, to utraciłby z nim niezbędne połączenie - wszak "zostałby" one w klasie bazowej. Z tego też powodu konstruktory nie są dziedziczone.
-destruktory - działanie destruktorów najczęściej także opiera się na polach prywatnych, a skoro one nie są dziedziczone zatem destruktor też nie powinien przechodzić do klas pochodnych.
-przeciążony operator przypisania (=) - opowiada za sposób, w jaki obiekt jest kopiowany w jednej zmiennej do drugiej . Taki transfer zazwyczaj również wymaga dostępu do pól prywatnych klasy, co odrazu odrazu wyklucza dziedziczenie.


Dziedziczenie - jak to wygląda?

Wewnętrznie używana przez kompilator definicja klasy pochodnej jest identyczna z tą, którą wpisujemy do kodu; nie zawiera żadnych pól i metod pochodzących z klas bazowych. Podczas tworzenia obiektu klasy pochodnej dokonywania jest także kreacja obiektu klasy bazowej, który staje się jego częścią. Zatem nasz obiekt pochodny to tak naprawdę obiekt bazowe plus dodatkowe pola, zdefiniowane w jego własnej klasie. Przy bardziej rozbudowanej hirachii klas zaczyna on przypominać cebule

konsekwencja ->
-> najpierw wywoływany jest konstruktor,"najbardziej bazowej" klasy danego obiektu, a potem te stosujące kolejno niżej w hierachii. Ponieważ klasa może posiadać więcej niż jeden konstruktor, kompilator musiałby podjąć decyzję, który z nich powinien zostać użyty. Nierobi tego jednak, lecz oczekuje, że będzie obecny domyślny kontruktor bezparametrowy (konieczność tę można obejść stosując tzw. listy inicjalizacyjne)
-> podstawie jeśli chodzi o destruktory, a one nie posiadają żadnych parametrów. Podczas niszczenia obiektów są one wywołane w kolejności od tego z klasy pochodnej do tych z klas bazowych.

Komentarze

Popularne posty z tego bloga

Kubernetes

Helm

Ansible Tower / AWX