P-Programowanie

Konstruktory

6 marca 2014, kategoria: C++

W języku C++ istnieje wiele rodzajów konstruktorów. Ich implementacja w klasach jest bardzo łatwa i nie sprawia problemów nawet początkującym programistom. Drobny problem z konstruktorami może pojawić się w bardziej zaawansowanych przypadkach np. podczas dziedziczenia.

Czym jest konstruktor?

Konstruktor to metoda, którą zawiera każda klasa. Jest ona wywoływana automatycznie podczas tworzenia instancji danej klasy. Konstruktor jest odpowiedzialny za inicjację klasy, czyli np. wypełnianie pól początkowymi wartościami.

Istnieje wiele rodzajów konstruktorów. Możemy definiować je jawnie, mamy wtedy pełną kontrolę nad jego wyglądem i zachowaniem. W przypadku braku konstruktora, zostanie on niejawny dodany do klasy automatycznie podczas kompilacji programu.

Dodanie konstruktora do klasy jest bardzo proste i polega na dodaniu do klasy metody o tej samej nazwie co klasa. Należy zapamiętać, aby nie podawać typu zwracanego.

Konstruktor domyślny (bezparametrowy)

Podstawowym rodzajem konstruktorów są konstruktory domyślne. Cechują się one brakiem jakichkolwiek parametrów – co za tym idzie, podczas tworzenia instancji danej klasy nie przekazujemy żadnych argumentów do konstruktora.

Po uruchomieniu powyższego programu, dwa razy wyświetli się napis konstruktor domyślny. Nie ma znaczenia czy obiekt tworzony jest statycznie czy dynamicznie, podczas tworzenia instancji klasy konstruktor i tak został wywołany.

Co ciekawe konstruktor domyślny może posiadać dowolną ilość parametrów, jednak wszystkie muszą mieć zdefiniowaną wartość domyślną (aby nie trzeba było podawać ich wartości podczas inicjacji klasy).

Mimo posiadania argumentów, konstruktor dalej jest nazywany domyślnym, ponieważ podanie argumentów nie jest wymagane.

Konstruktor wieloargumentowy

Jest to zwykły konstruktor najczęściej spotykany i najczęściej używany. Zawiera on listę argumentów, dzięki którym możliwa jest inicjacja pól podczas tworzenia obiektu.

Uruchomienie powyższego kodu nie uda się, ponieważ podczas tworzenia obiektu Arek, nie zostały podane wymagane argumenty. W przypadku obiektu Karol pola zostaną poprawnie zainicjowane a następnie wyświetlone w konsoli.

Aby naprawić powyższy program możemy zamienić konstruktor wieloargumentowy na konstruktor domyślny, dopisując domyślne wartości argumentów. Innym często stosowanym zabiegiem jest przeciążenie konstruktorów.

Przeciążanie konstruktorów

Konstruktory możemy przeciążać tak jak wszystkie inne metody. Nie jest to żaden błąd, raczej operacja często stosowana i spotykana w programach.

Konstruktor kopiujący

Konstruktor kopiujący jest przypadkiem szczególnym, ponieważ wywoływany jest tylko w momencie kopiowania danego obiektu. Przyjmuje on tylko jeden argument – referencję do swojej klasy. Jeżeli nie zdefiniujemy konstruktora kopiującego, zostanie od zdefiniowany niejawnie przez kompilator (nawet w przypadku gdy w klasie są też inne konstruktory).

W przykładzie, obiekt Karol zostanie skopiowany i wywoła się konstruktor kopiujący. Po wykonaniu programu wyświetlą się dane, którymi został zainicjowany obiekt Karol.

Po co jawnie implementować konstruktor kopiujący? Jest to niezbędne w przypadku klas zawierających wskaźniki. Podczas kopiowania obiektu, zostają skopiowane wszystkie wartości jego pól. Wartością zmiennej wskaźnikowej jest po prostu adres na jaki wskazuje, a więc zostaje skopiowany adres a nie wskazywana wartość.

Efektem tej niedogodności jest sytuacja, w której dwie różne kopie obiektów zawierają pola wskaźnikowe, wskazujące na ten sam adres (a więc obiekty nie są od siebie niezależne, bo modyfikacja jednego wpływa na stan drugiego).

Kiedy zostaje wywołany konstruktor kopiujący
  • podczas kopiowania obiektów
  • podczas przekazywania obiektu do funkcji przez wartość, ponieważ wtedy tworzona jest na stosie jego kopia

W innym artykule opisałem listę inicjalizacyjną C++, która jest poszerzeniem możliwości zwykłych konstruktorów. Artykuł może Cię zainteresować.

Komentarze:

Użytkownik Mariusz napisał/a:

08 marca 2014


Tworzysz naprawdę świetne materiały! Czy dałbyś radę zrobić coś o liście dwukierunkowej? : >

Użytkownik Karol napisał/a:

09 marca 2014


Temat listy wyczerpałem w artykule o liście jednokierunkowej. Dwukierunkowa ma jedynie dodatkowy wskaźnik na element poprzedzający.

Użytkownik Łukasz napisał/a:

22 sierpnia 2015


Może się czepiam:) ale
czy w ostatnim przykładzie nie są źle zaznaczone komentarze, dotyczące wywołania konstruktora kopiującego? bo fun(Arek) to wywołanie funkcji
pozdrawiam Dobre masz artykuły

Użytkownik Karol napisał/a:

24 sierpnia 2015


Cześć Łukasz
Napisalem w artykule, że wywołany zostaje drugi raz konstruktor kopiujacy. Napisałem tak, ponieważ podczas przekazywania argumentu do funkcji poprzez wartość automatycznie zostaje wywołany konstruktor kopiujacy. Gdyby argument został przesłany przez referencję lub wskaźnik , konstruktor kopiujacy nie wykona się.

Użytkownik Łukasz napisał/a:

25 sierpnia 2015


ok, zrozumiałem.

Użytkownik danjam napisał/a:

06 marca 2017


Można by też dodać opis konstruktora przenoszącego…..

Zachęcam Cię do zostawienia komentarza!

Ilość znaków: 0

Zachęcam Cię do polubienia bloga na facebooku! Dając lajka wspierasz moją pracę - wszystkie artykuły na blogu są za darmo!