[ Pobierz całość w formacie PDF ]
.Dzięki temu wywoływany dwukrotnie przed zakończeniem programu destruktor niszczy za każdym razem inny obiekt.Uwaga.Instrukcję Poprawna z2 = z1; można także zapisać w postaci Poprawna z2(z1);, pokazującej wyraźnie, że obiekt z2 jest inicjowany obiektem z1.7.5.3.Przekazywanie obiektów do/z funkcjiSyntaktyka i semantyka przekazywania obiektów do funkcji jest identyczna dla obiektów typów predefiniowanych (np.int, double), jak i obiektów klas definiowanych przez użytkownika.Dla typu zdefiniowanego przez użytkownika parametr formalny funkcji będzie klasą, wskaźnikiem, lub referencją do klasy.Funkcję taką wywołujemy z parametrem aktualnym, będącym odpowiednio obiektem danej klasy, adresem obiektu, lub zmienną referencyjną.Podobnie jak dla typów wbudowanych, obiekty klas są domyślnie przekazywane przez wartość, a semantyka przekazywania jest taka sama, jak semantyka inicjowania.Obiekty przekazywane do funkcji tworzone są jako automatyczne, tzn.takie, które tworzy się za każdym razem gdy jest wykonywana ich instrukcja deklaracji, i niszczy za każdym razem, gdy sterowanie opuszcza blok zawierający deklarację.Jeżeli funkcja jest wywoływana wiele razy (co często się zdarza), to tyle samo razy jest wykonywane tworzenie i niszczenie obiektów, a więc za każdym razem mamy nowy obiekt, z nowymi inicjalnymi wartościami zmiennych składowych.Pokazany niżej przykład ilustruje przekazywanie obiektu do funkcji przez wartość.Przykład 6.22.#include <iostream.h>class Test {public:Test(int a): x(a) { cout << Konstrukcja.\n; }Test(const Test& t){ this->x = t.x; cout << Konstrukcja kopii.\n; }~Test() { cout << Destrukcja.\n; }int podaj() { return x; }void ustaw(int i) { x = i; }private:int x;};void f(Test arg) {arg.ustaw(50);cout << Funkcja f: ;cout << t1.x == << arg.podaj() << '\n';}int main() {Test t1(10);cout << t1.x == << t1.podaj() << '\n';f(t1);cout << t1.x == << t1.podaj() <<'\n';return 0;}Wydruk z programu ma postać:Konstrukcja.t1.x == 10Konstrukcja kopii.Funkcja f: t1.x == 50Destrukcja.t1.x == 10Destrukcja.Analiza programu.Wykonanie instrukcji deklaracji Test t1(10); tworzy obiekt t1 za pomocą konstruktora Test(int), od którego pochodzi pierwszy wiersz wydruku.W instrukcji cout wywołuje się funkcję składową podaj(), która wyświetla drugi wiersz wydruku.Instrukcja wywołania funkcji f(t1), z argumentem przekazywanym przez wartość, wywołuje konstruktor kopiującyTest(const Test&), który generuje trzeci wiersz wydruku.Czwarty wiersz jest generowany przez funkcję f(); wypisuje ona wartość pola x lokalnej kopii argumentu, tj.obiektu utworzonego przez konstruktor kopiujący.Zauważmy, że wartość x w kopii obiektu została zmieniona na 50 funkcją składową ustaw(), wywołaną z bloku funkcji f(), co pokazuje czwarty wiersz wydruku.Po wydrukowaniu czwartego wiersza sterowanie opuszcza blok funkcji f(), wywołując destruktor ~Test(), który niszczy obiekt, utworzony przez konstruktor kopiujący (piąty wiersz z tekstem Destrukcja.).Po opróżnieniu stosu funkcji f() sterowanie wraca do bloku main(), wywołując w instrukcji cout funkcję składową podaj() obiektu t1.Wykonanie tej instrukcji pokazuje, że wartość pola x pozostała bez zmiany, jako że zmiana xna 50 była wykonywana przez funkcję f() na kopii obiektu t1, a nie na samym obiekcie.Ostatni wiersz wydruku sygnalizuje destrukcję obiektu t1, gdy sterowanie opuszcza blok funkcji main().W powyższym przykładzie warto zwrócić uwagę na dwa momenty.Gdy jest tworzona kopia obiektu przekazywanego do argumentu formalnego funkcji, nie wywołuje się konstruktora obiektu, lecz konstruktor kopiujący
[ Pobierz całość w formacie PDF ]