Pobierz prezentację
Pobieranie prezentacji. Proszę czekać
1
Programowanie obiektowe
PO Programowanie obiektowe PO - LAB 5 Wojciech Pieprzyca
2
Konstruktor kopiujący (I)
PO Konstruktor kopiujący (I) Konstruktor kopiujący to specyficzny rodzaj konstruktora wykorzystywany przez kompilator zawsze wtedy, gdy istnieje konieczność utworzenia identycznej kopii istniejącego obiektu. Taka potrzeba występuje w kilku sytuacjach: Niejawnie, gdy funkcja przyjmuje jako argument obiekt przekazywany przez wartość np. void fun(osoba os). Na potrzeby lokalnych operacji w ramach funkcji fun tworzona jest kopia obiektu os. Niejawnie, gdy funkcja zwraca jako wartość jakiś obiekt. Instrukcja return występująca w ramach funkcji i zwracająca określoną wartość (obiekt), również wymaga utworzenia kopii lokalnego obiektu, która będzie zwrócona przez funkcję i widoczna na zewnątrz funkcji. np. osoba fun() Kiedy jawnie zażądamy utworzenia kopii obiektu. np. osoba os1; osoba os2 = os1; lub osoba os2 = osoba(os1);
3
Konstruktor kopiujący (II)
PO Konstruktor kopiujący (II) Definiowanie konstruktora kopiującego Konstruktor kopiujący jako argument musi przyjąć referencję do obiektu klasy w której definiujemy konstruktor czyli klasa::klasa (klasa &wzor). Przekazany obiekt będzie wzorem na podstawie którego powstanie kopia obiektu. Czy tworzenie konstruktora kopiującego jest konieczne ? Jeżeli sami nie zdefiniujemy konstruktora kopiującego dla klasy, to kompilator zrobi to za nas. Posłuży się on prostą metodą kopiowania składowych - składnik po składniku. Nie zawsze taka metoda tworzenia kopii obiektu jest dobra. Zawodzi ona szczególnie wówczas, gdy obiekt zawiera zmienne (obiekty) lub tablice tworzone dynamicznie. Rozważymy to w dalszej części prezentacji.
4
Konstruktor kopiujący (III)
PO Konstruktor kopiujący (III) Przykład tego co tworzy kompilator, gdy sami nie zdefiniujemy konstruktora kopiującego. Napiszemy klasę z konstruktorem kopiującym identycznym z tym jaki zazwyczaj tworzy kompilator za nas. class samochod { private: char marka[20]; char model[20]; int rocznik; float pojemnosc; public: samochod (samochod &wzor); };
5
Konstruktor kopiujący (IV)
PO Konstruktor kopiujący (IV) samochod::samochod (samochod &wzor) { strcpy(marka, wzor.marka); strcpy(marka, wzor.model); rocznik = wzor.rocznik; pojemnosc = wzor.pojemnosc; cout << ”Dziala konstruktor kopiujacy” << endl; } Jak widzimy w zdefiniowanym konstruktorze kopiującym zastosowano metodę kopiowania składowych składnik po składniku. Taką metodę stosuje sam kompilator, więc w zasadzie, gdybyśmy nie zdefiniowali powyższego konstruktora kopiującego to nic by się nie stało, zrobiłby to za nas kompilator i efekt byłby identyczny.
6
Konstruktor kopiujący (V)
PO Konstruktor kopiujący (V) Dodatkowo określimy dwie funkcję, która przyjmuje jako argument lub zwracają jako wartość obiekt typu samochod. void fun(samochod s) { cout << ”Dziala funkcja fun” << endl; } samochod fun2(samochod s) cout << ”Dziala funkcja fun2” << endl; return s;
7
Konstruktor kopiujący (VI)
PO Konstruktor kopiujący (VI) //Uwaga. Należy samodzielnie stworzyć konstruktor klasy samochód //oraz metodę pokaż informującą o parametrach samochodu int main() { samochod s1("honda","accord",2005,2.0); s1.pokaz(); //tutaj zadziała konstruktor kopiujący po raz pierwszy samochod s2 = s1; s2.pokaz(); //tutaj 2 raz fun(s1); //tutaj 3 i 4 raz samochod s3 = fun2(s1); getch(); }
8
Konstruktor kopiujący (VII)
PO Konstruktor kopiujący (VII) Zdefiniujmy klasę telefon w której zawarta będzie dynamiczna tablica kontaktów zawierająca dowolne 5 numerów. class telefon { private: string numer; string model; string *lista; int n; //n - ilość numerów na liście public: telefon(string _numer, string _model); }; telefon::telefon(string _numer, string _model) numer = _numer; model = _model; lista = new string[5]; n = 0; }
9
Konstruktor kopiujący (VIII)
PO Konstruktor kopiujący (VIII) W konstruktorze tej klasy rezerwowana jest pamięć do przechowywania 5 numerów (obiektów klasy String). Jeżeli pozwolilibyśmy kompilatorowi samodzielnie stworzyć konstruktor kopiujący (innymi słowy sami byśmy go nie zdefiniowali) to kopiowanie odbyłoby się metodą składnik po składniku czyli: telefon::telefon(telefon &wzor) { numer = wzor.numer; model = wzor.model; lista = wzor.lista; n = wzor.n; } Pułapka znajduje się w ostatniej linii tego konstruktora. Zmienna lista tak naprawdę zawiera adres początku tablicy w której przechowywane są numery. A więc po utworzeniu kopii obiektu i skopiowaniu listy w ten sposób, drugi obiekt nie będzie miał nowej listy, ponieważ będzie on operował na liście obiektu wzorcowego, której adres został skopiowany. Czyli mimo, że mamy dwa obiekty, to będzie istnieć tylko jedna lista, a przecież nie tego oczekujemy.
10
Konstruktor kopiujący (IX)
PO Konstruktor kopiujący (IX) Możemy zapobiec opisanej wadzie domyślnego konstruktora kopiującego, tworząc własny konstruktor, który będzie uwzględniał konieczność zarezerwowania pamięci dla nowej listy. telefon::telefon(telefon &wzor) { numer = wzor.numer; model = wzor.model; lista = new string[5]; n = wzor.n; for (int i=0; i<n; i++) lista[i] = wzor.lista[i]; } W tym przypadku utworzona została nowa lista do której skopiowano wszystkie wartości z listy obiektu wzorcowego.
11
Konstruktor kopiujący (X)
PO Konstruktor kopiujący (X) Ćwiczenie 1) Proszę dopisać do klasy telefon metodę dodajNumer(String numer), która umieści nowy numer na pozycji n listy oraz metodę pokaz, która wyświetli numer telefonu, jego markę oraz listę kontaktów (wszystkie 5 kontaktów nawet jeżeli nie ma tylu na liście). 2) Dla klasy telefon, pozbawionej konstruktora kopiującego, proszę stworzyć obiekt typu telefon (t1), dodać do jego listy trzy numery telefonów, a następnie stworzyć kopię tego obiektu (t2). Proszę sprawdzić co po tych operacjach zawierają listy w obiektach t1 i t2. Następnie proszę dodać numer telefonu na liście obiektu t1 i ponownie sprawdzić zawartość list obu telefonów. Powinno okazać się, że dodanie czegoś na listę t1 powoduje, że zmienia się również lista związana z obiektem t2. 3) Proszę dodać prawidłową wersję konstruktora kopiującego (poprzedni slajd) i wykonać takie same instrukcje jak w pkt. 2. Tym razem obie list powinny być autonomiczne i zmiana na jednej z nich nie powinna wpływać na drugą.
Podobne prezentacje
© 2024 SlidePlayer.pl Inc.
All rights reserved.