• Nie Znaleziono Wyników

Konstruktory w klasach pochodnych

W dokumencie Język C++ – podstawy programowania (Stron 108-114)

5.5. Konstruktory w klasach pochodnych

Konstruktory i destruktory nie są dziedziczone. Konstruktory oraz de-struktory można tworzyć dla klas bazowych, dla klas pochodnych oraz dla obu z nich jednocześnie. Gdy tworzony jest obiekt klasy pochodnej, wywo-ływany jest najpierw konstruktor klasy bazowej (o ile istnieje), a następnie konstruktor klasy pochodnej. Podczas tworzenia obiektu klasy pochodnej, aby zainicjować dane składowe klasy podstawowej musi zostać wywołany jej konstruktor. Jednak możliwe jest ich wywołanie odpowiednio w konstrukto-rach i operatokonstrukto-rach przypisania klasy pochodnej. Wywoływanie konstruktora klasy bazowej zilustrujemy przykładem.

Listing 5.5. klasa pochodna i konstruktory

1#include <i o s t r e a m . h>

5.5. Konstruktory w klasach pochodnych 99

23 private: double z ;

25 } ;

27 i n t main ( )

{punktB p1 ( 5 , 5 0 , 5 0 ) ;

29 p1 . pokaz ( ) ; g e t c h ( ) ;

31 return 0 ;

}

Po uruchomieniu tego programu mamy następujący wydruk:

x = 50 y = 50

z = 5

Klasa bazowa punkt ma postać:

c l a s s punkt // k l a s a bazowa

{

public:

punkt (double xx , double yy ) {x = xx ; y = yy ; } void pokazXY ( ) ;

private: double x , y ; } ;

Konstruktor klasy bazowej ma postać:

punkt ( double xx , double yy ) { x = xx ; y = yy ; }

i wymaga dwóch argumentów dla inicjacji składowych x i y. Klasa pochodna punktB zawiera dodatkową daną z i ma postać:

c l a s s punktB : public punkt // k l a s a pochodna {

public:

punktB (double k , double m, double n ) : punkt (m, n ) { z = k ; }

void pokaz ( ) { pokazXY ( ) ;

c o u t << " z ␣=␣ ␣ ␣ " << z << e n d l ; }

private: double z ; } ;

Konstruktor klasy pochodnej ma postać:

100 5. Dziedziczenie i hierarchia klas

punktB ( double k , double m, double n ) : punkt ( m, n )

{ z = k ; }

Konstruktor punktB musi wywołać konstruktor punkt, który jest odpowie-dzialny za zainicjowanie tej części obiektu klasy punktB, która pochodzi z klasy podstawowej punkt. W tym celu został wykorzystany tzw. inicjator składowej. Zastosowano rozszerzoną postać deklaracji konstruktora klasy pochodnej, która pozwala przekazywać argumenty do jednego lub kilku kon-struktorów klasy bazowej.

Formalna postać rozszerzonej deklaracji jest następująca:

konstruktor_klasa_pochodna ( l i s t a _ p a r a m e t r o w ) : nazwa_klasy_pochodnej_1 ( l i s t a argumentow ) , : nazwa_klasy_pochodnej_2 ( l i s t a argumentow ) ,

. . . . : nazwa_klasy_pochodnej_N ( l i s t a argumentow ) , {

// c i a l o k o n s t r u k t o r a k l a s y p o c h o d n e j }

Przy pomocy znaku dwukropka oddzielamy deklarację konstruktora klasy pochodnej od specyfikacji klasy bazowej. Gdy mamy więcej klas bazowych dziedziczonych przez klasę pochodną, używamy przecinka, do oddzielenia ich specyfikacji. W naszym przykładzie mamy tylko jedną klasę bazową, która ma dwa parametry, wobec czego mamy napis:

: punkt (m, n )

Jak wiec widzimy, nasz konstruktor klasy pochodnej jest funkcją o trzech argumentach, dwa argumenty muszą być przesłane do konstruktora klasy bazowej. W momencie utworzenia obiektu p1:

punktB p1 ( 5 , 5 0 , 50 ) ;

następuje przekazanie argumentów aktualnych 50 i 50 do konstruktora klasy bazowej i wykonanie konstruktora:

punkt ( xx , yy )

a następnie wykonanie konstruktora klasy pochodnej. Bardzo często zacho-dzi sytuacja, gdy tworzone są obiekty klasy pochodnej a klasa bazowa i klasa pochodna zawierają różne składowe. Jeżeli tworzony jest obiekt klasy pochodnej to kolejność wywoływania konstruktorów jest następująca:

— Wywoływane są konstruktory obiektów klasy bazowej

— Wywoływany jest konstruktor klasy bazowej

5.5. Konstruktory w klasach pochodnych 101

— Wywoływany jest konstruktor klasy pochodnej

— Destruktory wywoływane są w odwrotnej kolejności

Zagadnienie kolejności wywoływania konstruktorów zilustrujemy kolej-nym przykładem, w którym dwie klasy – bazowa i pochodna posiadają własne konstruktory i destruktory. Klasą bazową jest klasa punkt, której danymi chronionymi są współrzędne punktu, klasa pochodna kolo ma jedną daną prywatną, jest nią promień koła. Moment wywoływania konstrukto-rów i destruktokonstrukto-rów będzie wypisywany na ekranie w trakcie wykonywania funkcji testującej. Dla celów dydaktycznych, program składa się z 5 plików:

deklaracji klasy punkt, definicja klasy punkt, deklaracja klasy pochodnej kolo, definicja klasy kolo oraz funkcji testującej.

Zmienne x i y są danymi chronionymi klasy bazowej punkt. Definicja klasy pokazana jest na wydruku.

Listing 5.6. klasa pochodna - konstruktory

1 // p l i k " p u n k t . h"

// d e k l a r a c j a k l a s y p u n k t

3

#i f n d e f _PUNKT_H

5#define _PUNKT_H

7 c l a s s punkt {

9 public :

punkt (double = 0 . 0 , double = 0 . 0 ) ; // k o n s t r u k t o r domyslny

11 ~punkt ( ) ; // d e s t r u k t o r

protected:

13 double x , y ; } ;

15

#endif

Klasa posiada konstruktor domyślny i destruktor:

punkt ( double = 0 . 0 , double = 0 . 0 ) ; // k o n s t r u k t o r domyslny

~punkt ( ) ; // d e s t r u k t o r

W definicji klasy bazowej punkt, konstruktor jak i destruktor wyświetlają komunikat o obiekcie, na rzecz którego zostały wywołane. Deklaracja kla-sy punkt umieszczona jest umieszczona w odrębnym pliku i pokazana na wydruku.

Listing 5.7. klasa pochodna - konstruktory

// p l i k p u n k t . cpp

2 // d e f i n i c j a k l a s y p u n k t

102 5. Dziedziczenie i hierarchia klas

#include <i o s t r e a m . h>

4#include " punkt . h"

6 punkt : : punkt (double xx , double yy ) {

8 x = xx ; y = yy ;

c o u t << " k o n s t r u k t o r ␣ o b i e k t u ␣ k l a s y ␣ punkt ␣ ";

10 c o u t << " x=␣ " << x << " ␣ ␣ y=␣ " << y << e n d l ; }

12

punkt : : ~ punkt ( )

14 {

c o u t << " ␣ d e s t r u k t o r ␣ o b i e k t u ␣ k l a s y ␣ punkt ␣ ";

16 c o u t << " x=␣ " << x << " ␣ ␣ y=␣ " << y << e n d l ; }

Klasa pochodna kolo dziedziczy od klasy bazowej punkt i jej deklaracja pokazana jest na wydruku. Składowa klasy pr zadeklarowana została jako prywatna.

Listing 5.8. klasa pochodna - konstruktory

1 // p l i k " k o l o . h"

// d e k l a r a c j a k l a s y k o l o

3

#i f n d e f _KOLO_H

5#define _KOLO_H

7#include " punkt . h"

9 c l a s s k o l o : public punkt {

11 public :

k o l o (double r =0.0 , double xx =0.0 , double yy =0.0) ;

13 // k o n s t r u k t o r domyslny

~ k o l o ( ) ; // d e s t r u k t o r

15 private: double pr ;

17 } ;

19#endif

Klasa kolo posiada konstruktor i destruktor:

k o l o ( double r =0.0 , double xx =0.0 , double yy =0.0) ; // k o n s t r u k t o r domyslny

~ k o l o ( ) ; // d e s t r u k t o r

Na kolejnym wydruku pokazana jest definicja klasy pochodnej kolo.

5.5. Konstruktory w klasach pochodnych 103 Listing 5.9. klasa pochodna - konstruktory

1 // p l i k " k o l o . cpp "

Konstruktor klasy kolo wywołuje równocześnie konstruktor klasy punkt :

Listing 5.10. klasa pochodna; konstruktory; funkcja testująca

#include <i o s t r e a m . h>

2#include <c o n i o . h>

#include " punkt . h"

4#include " k o l o . h"

104 5. Dziedziczenie i hierarchia klas

}

16 g e t c h ( ) ;

return 0 ;

18 }

Przykładowy program pokazany na wydrukach 5.6 – 5.10 składa się z 5 plików, jego schemat fizyczny pokazano na rysunku. Fizyczną strukturę każdego programu C++ można określić jako zbiór plików. Niektóre z nich będą plikami nagłówkowymi(.h), a inne plikami implementacji (.cpp). Przyj-muje się, że komponent jest najmniejszym elementem projektu fizycznego.

Strukturalnie komponent stanowi niepodzielną jednostkę fizyczną, której części nie mogą być użyte niezależnie od pozostałych. Komponent składa się z jednego pliku nagłówkowego i jednego pliku implementacji. Graficzne przedstawienie komponentów znacznie ułatwia zbadanie wzajemnych rela-cji pomiędzy plikami i bibliotekami. W omawianym przykładzie, w funkrela-cji main() tworzony jest obiekt p1 klasy bazowej punkt. Następnie tworzone są kolejno dwa obiekty k1 i k2 klasy pochodnej kolo. Po uruchomieniu funkcji testującej mamy następujący wynik:

Na początku tworzony jest egzemplarz obiektu klasy punkt. Wywoływa-ny jest konstruktor a potem destruktor. Następnie tworzoWywoływa-ny jest obiekt k1 klasy pochodnej kolo. Wywoływany jest najpierw konstruktor klasy punkt, który pokazuje przekazane wartości a następnie wywołany jest konstruktor klasy kolo, który też pokazuje przekazane wartości. Kolejno wywoływany jest destruktor klasy koło i destruktor klasy punkt (wywoływanie destruk-torów odbywa się w odwrotnej kolejności). Następnie utworzony zostaje kolejny obiekt k2 klasy kolo.

W dokumencie Język C++ – podstawy programowania (Stron 108-114)