background image

4. Konstruktory i destruktory.

Zadania konstruktora 
Wywołanie konstruktora powoduje wykonanie następujących zadań:

obliczenie rozmiaru obiektu 

alokacja obiektu w pamięci 

wyczyszczenie (zerowanie) obszaru pamięci zarezerwowanej dla obiektu (tylko w 
niektórych językach) 

wpisanie do obiektu informacji łączącej go z odpowiadającą mu klasą (połączenie z 
metodami klasy) 

wykonanie kodu klasy bazowej (w niektórych językach nie wymagane) 

wykonanie kodu wywołanego konstruktora 

Z wyjątkiem ostatniego punktu powyższe zadania są wykonywane wewnętrznie i są wszyte 
w kompilator lub interpreter języka, lub w niektórych językach stanowią kod klasy 
bazowej.

W językach programowania w różny sposób oznacza się konstruktor:

w C++, Javie, C# - jest to metoda o nazwie zgodnej z nazwą klasy 

w Pascalu - metoda której nazwę poprzedzono słowem kluczowym constructor

W języku C++ wyróżnia się następujące szczególne rodzaje konstruktorów: 

konstruktor domyślny,

zwykły konstruktor,

konstruktor kopiujący,

konstruktor konwertujący,

Zwykły konstruktor

Konstruktor, który można wywołać, podając co najmniej jeden parametr. Jest to 

zwykły   konstruktor   stworzony   przez   twórcę   klasy.   Jego   zadeklarowanie   w   C++   nie 
powoduje niejawnego generowania konstruktora domyślnego. Z reguły parametry takiego 
zwykłego   konstruktora   spełniają   funkcję   inicjalizatorów,   które   przypisują   odpowiednie 
wartości wewnętrznym zmiennym tworzonego obiektu, np. (przykład w C++):

class Wektor { 
  public:
    Wektor( double x , double y ) {
      this->x = x;
      this->y = y;
    }
  private:

background image

    double x;
    double y;
};

int main () {
  Wektor mojWektor( 3 , 2 );
  return 0;
}

Właściwości i ciekawostki 

W większości języków konstruktor nie może być wirtualny(w efekcie czego nie może 
być metodą czysto wirtualną). 

Konstruktor nie może być statyczny

W   klasie,   gdzie   zadeklarowany   jest   konstruktor   kopiujący,   powinien   być 
zadeklarowany dowolny inny konstruktor (domyślny lub inny), ponieważ nie byłoby 
możliwe   stworzenie   obiektu   danej   klasy.   Aby   stworzyć   obiekt   korzystając   z 
konstruktora kopiującego, należałoby posiadać inny egzemplarz obiektu danej klasy, 
który   nie   może   być   utworzony,   ponieważ   jego   stworzenie   również   wymagałoby 
egzemplarza danej klasy itd. 

W klasie, gdzie wymagane jest istnienie: konstruktora kopiującego lub destruktora 
lub operatora przypisania, wymagane jest najczęściej istnienie wszystkich trzech. 

Parametr   konstruktora   kopiującego   nie   może   być   przekazywany  

przez   wartość, 

ponieważ   powodowałoby  to   nieskończone   wywołanie   konstruktorów   kopiujących. 
Dla   potrzeb   wywołania   konstruktora   należałoby   wykonać   kopię   obiektu.   Aby 
wykonać kopię obiektu należy wywołać jego konstruktor kopiujący, któremu również 
należy przekazać obiekt przez wartość, a więc wykonać jego kopię, itd. Błąd ten nie 
przejdzie   procesu   kompilacji,   kompilator   rozpoznaje   taki   przypadek   i   generuje 
sygnał   błędu.   Nie   jest   możliwe   wygenerowanie   nieskończonej   pętli   wywołań, 
ponieważ   ciąg   takich   wywołań   miałby   teoretycznie   nieskończoną   długość   i 
spowodowałby zablokowanie kompilatora. 

Aby uniemożliwić stworzenie obiektu danej klasy należy: 

zadeklarować   wszystkie   konstruktory   w   sekcji   prywatnej   (konstruktor 
kopiujący może ale nie musi spełniać tego warunku) 

klasa nie może deklarować przyjaźni z klasą ani funkcją

Działanie takie stosuje się, gdy na przykład klasa ma służyć jako zbiór metod i pól 
statycznych i nie jest potrzebny jakikolwiek egzemplarz obiektu danej klasy (również 
jako klasy bazowej).  

Destruktor  - w obiektowych językach programowania specjalna metoda, wywoływana 
przez program przed usunięciem obiektu i niemal nigdy nie jest wywoływana wprost w 
kodzie   używającym   obiektu.   Pod   względem   funkcjonalnym   jest   to   przeciwieństwo 

background image

konstruktora.

Destruktor ma za zadanie wykonać czynności składające się na jego "zniszczenie", 

inne   niż   zwolnienie   pamięci   zajmowanej   przez   sam   obiekt,   przygotowujące   obiekt   do 
fizycznego   usunięcia.   Po   jego   wykonaniu   obiekt   znajduje   się   w   stanie   osobliwym   i 
zazwyczaj nie można już z tym obiektem zrobić nic poza fizycznym usunięciem. Destruktor 
zwykle wykonuje takie czynności, jak zamknięcie połączenia z plikiem/gniazdem/potokiem, 
odrejestrowanie się z innych obiektów, czasem również zanotowanie faktu usunięcia, a 
także usunięcie obiektów podległych, które obiekt utworzył lub zostały mu przydzielone 
jako   podległe   (jeśli   jest   ich   jedynym   właścicielem)   lub   wyrejestrowanie   się   z   jego 
użytkowania (jeśli jest to obiekt przezeń współdzielony).

W   większości   języków   programowania   (np   C++,   Object   Pascal)   destruktor   jest 

dziedziczony jak każda inna metoda. 

Przykładowy destruktor (w składni C++):

  class Samochod{
    public:
      string marka;
      //... (pewne dane i metody)
      ~Samochod() { //destructor
        std::cout << "Samochod " << marka << " zostal usuniety.\n";
      }
  };

Finalizator

W niektórych językach z wbudowanym odśmiecaczem (np. Java i C#) dostępna jest 

składnia   finalizatora   -   specjalnej   metody   wywoływanej,   gdy   obiekt   jest   usuwany   przy 
odśmiecaniu.   W   przeciwieństwie   do   destruktora   nie   wiadomo   w   którym   dokładnie 
momencie działania programu to nastąpi.


Document Outline