Konstruktor kopiujący



Podobne dokumenty
Niejawne funkcje składowe

Wstęp do Programowania 2

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 28 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 13 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 30

Programowanie obiektowe - Przykładowe zadania egzaminacyjne (2005/2006)

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

PARADYGMATY PROGRAMOWANIA Wykład 3

Programowanie obiektowe Wykład 3. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Programowanie obiektowe w języku C++ dr inż. Jarosław Forenc

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Programowanie obiektowe w C++ Wykład 12

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy WSKAŹNIKI KLASOWE

Operatory na rzecz typu TString

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

Nowe słowa kluczowe. Komentarze. Wskaźniki typu void. class, delete, new, friend,... /* Komentarz w C i C++ */ // Komentarz w C++ (do końca wiersza)

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Jzyk C++ cz 3. Jarosław Gramacki Instytut Informatyki i Elektroniki ( $)*)+' *, - ( ' )*'.' '',*/ *, ','*0) 1 / ) %*+ 2'' 2" ( $%%) )'20 )*0) 1 / )

Język C++ wykład VI. uzupełnienie notatek: dr Jerzy Białkowski. Programowanie C/C++ Język C++ wykład VI. dr Jarosław Mederski.

public: // interfejs private: // implementacja // składowe klasy protected: // póki nie będziemy dziedziczyć, // to pole nas nie interesuje

Szablony klas, zastosowanie szablonów w programach

Projektowanie klas c.d. Projektowanie klas przykład

PARADYGMATY PROGRAMOWANIA Wykład 4

Zaawansowane programowanie w języku C++ Klasy w C++

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

Programowanie obiektowe, wykład nr 6. Klasy i obiekty

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Dla każdej operacji łącznie tworzenia danych i zapisu ich do pliku przeprowadzić pomiar czasu wykonania polecenia. Wyniki przedstawić w tabelce.

Programowanie w języku C++

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

wykład IV uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C, a C++. wykład IV dr Jarosław Mederski Spis Język C++ - wstęp

Programowanie w języku C++

Przeciążenie operatorów

Informatyka 2. Wykład nr 3 ( ) Politechnika Białostocka. - Wydział Elektryczny. dr inŝ. Jarosław Forenc

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 15 kwietnia K.Grzelak (Wykład 8) Programowanie w C++ 1 / 33

wykład V uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C++ klasy i obiekty wykład V dr Jarosław Mederski Spis Język C++ - klasy

Programowanie w C++ Wykład 14. Katarzyna Grzelak. 3 czerwca K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27

Programowanie obiektowe i C++ dla matematyków

Operator przypisania. Jest czym innym niż konstruktor kopiujący!

Funkcje przeciążone, konstruktory kopiujące, argumenty domyślne

Język C++ wykład VIII

TEMAT : KLASY DZIEDZICZENIE

Wykład 4: Klasy i Metody

PROE wykład 3 klasa string, przeciążanie funkcji, operatory. dr inż. Jacek Naruniec

Programowanie obiektowe i C++ dla matematyków

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Programowanie Obiektowo Zorientowane w języku C++ Klasy, pola, metody

Wyliczanie wyrażenia obiekty tymczasowe

Język C++ wykład VII. uzupełnienie notatek: dr Jerzy Białkowski. Programowanie C/C++ Język C++ wykład VII. dr Jarosław Mederski. Spis.

KLASY cz4. Dorota Pylak. destruktory składowe statyczne przeciążanie operatorów. wskaźniki

Wykład 8: klasy cz. 4

Programowanie, część I

Programowanie Obiektowe i C++

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Plik klasy. h deklaracje klas

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Podstawy programowania skrót z wykładów:

Wstęp do Programowania 2

Programowanie komputerowe. Zajęcia 5

Programowanie obiektowe. Dr hab. Inż. Marta Gładysiewicz-Kudrawiec Pokój 229 A1 Operatory new delete pliki-odczyt

Programowanie w C++ Wykład 9. Katarzyna Grzelak. 14 maja K.Grzelak (Wykład 9) Programowanie w C++ 1 / 30

Dzisiejszy wykład. Klasa string. wersja prosta wersja ze zliczaniem odwołań. Wyjątki Specyfikator volatile Semafory

Języki i paradygmaty programowania Wykład 2. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/18

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Programowanie obiektowe

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) { zdefiniuje. Integer::operator=(ri);

Programowanie 2. Język C++. Wykład 3.

Wstęp do Programowania 2

Programowanie, część I

Wskaźniki. nie są konieczne, ale dają językowi siłę i elastyczność są języki w których nie używa się wskaźników typ wskaźnikowy typ pochodny:

Modelowanie numeryczne w fizyce atmosfery Ćwiczenia 3

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Programowanie obiektowe. Materiały przygotował: mgr inż. Wojciech Frohmberg

Programowanie Obiektowew języku C++ Zadania L4

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne

Szablony funkcji i szablony klas

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Wskaźniki. Informatyka

Programowanie Obiektowo Zorientowane w języku c++ Konstruktory

DYNAMICZNE PRZYDZIELANIE PAMIECI

PROGRAMOWANIE OBIEKTOWE W C++ cz. 2. Dziedziczenie, operacje wej cia-wyj cia, przeładowanie operatorów.

PARADYGMATY PROGRAMOWANIA Wykład 2

ROZDZIAŁ 2. Operatory

Materiały do zajęć VII

EGZAMIN 2 (14 WRZEŚNIA 2015) JĘZYK C++

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

Programowanie Obiektowe i C++

Wykład V. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

Wykład I. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

Programowanie obiektowe Wykład 1. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/20

Język C++ Różnice między C a C++

Wzorce funkcji (szablony)

Transkrypt:

Konstruktor kopiujący Konstruktor kopiujący jest wywoływany wtedy, kiedy nowo tworzony obiekt jest inicjowany już istniejącym obiektem tej samej klasy: inicjujemy nowy obiekt istniejącym obiektem Punkt a(1,1), b(a); // definicja obiektu b za pomocą a Punkt c=a(1,1); Punkt d=punkt(a); Punkt *wpunkt = new Punkt(a); przekazujemy obiekt do funkcji przez wartość nowy obiekt jest kopią funkcja(a); // przekazanie obiektu a do funkcji zwracamy obiekt z funkcji przez wartość c=funkcja(); // zwrócenie obiektu z funkcji Jeśli użytkownik takiego konstruktora nie dostarczy, to stosowany jest domyślny konstruktor kopiujący, wykonujący dokładną, bit po bicie kopię obiektu. Przykład: class Ulamek int l; // licznik int m; // mianownik... public: Ulamek(int a=0, int b=1) // Konstruktor inicjujący... ; Ulamek f0, f1(1), f2(6,3), f3(f2); Tutaj będzie użyty konstruktor kopiujący Tutaj będzie użyty odpowiedni konstruktor inicjujący W klasie Ulamek brak jest konstruktora kopiującego. Kompilator utworzy własny konstruktor kopiujący. Pytanie: Czy domyślny konstruktor kopiujący zawsze zrobi to co trzeba? 1

Kiedy potrzebny jest własny konstruktor kopiowania? Przykład: tablica dynamiczna, zdefiniowany jest tylko konstruktor inicjujący. #include <iostream> using namespace std; class Tablica int lelem; // liczba elementów tablicy double *T ; // wskaźnik do obszaru przydzielonego dla tablicy public : Tablica (int n) T = new double [lelem = n] ; cout << "++ Konstruktor - adres obiektu: " << this << " - adres tablicy: " << T << "\n" ; ~Tablica () cout << "-- Destruktor - adres obiektu: " << this << " - adres tablicy: " << T << "\n" ; delete [] T ; friend void func(tablica b); ; void func (Tablica b) cout << "*** func: Działam na kopii - adres obiektu: " << &b <<" - adres tablicy: " << b.t <<endl; int main() Tablica a(4) ; cout << "** Zaczynam main **" << endl; cout << "** Wywołuję func **\n" ; func (a) ; cout << "** Kończę main **" << endl; return 0; Jak wygląda przebieg programu? ++ Konstruktor - adres obiektu: 0xbffffc70 - adres tablicy: 0x8049f50 ** Zaczynam main ** ** Wywołuję func ** *** func: Działam na kopii - adres obiektu: 0xbffffc60 - adres tablicy: 0x8049f50 -- Destruktor - adres obiektu: 0xbffffc60 - adres tablicy: 0x8049f50 ** Kończę main ** -- Destruktor - adres obiektu: 0xbffffc70 - adres tablicy: 0x8049f50 Gdzie jest pułapka? 2

Jak działa konstruktor kopiujący? Domyślny konstruktor kopiujący przepisuje kolejno wartość każdej składowej do jej odpowiednika w nowo tworzonym obiekcie. Jest to tzw. kopiowanie płytkie (ang. memberwise copying, shallow copying). W przypadku obiektów o składowych dynamicznych potrzebne jest kopiowanie głębokie zapewniane przez własny konstruktor kopiujący. Konstruktor taki ma prototyp: MojaKlasa(const MojaKlasa &); Przykład: #include <iostream> class Tablica int lelem ; double * T ; public : Tablica (int n) T = new double [lelem = n] ; ~Tablica () delete [] T ; //////////////////////////////////////////////////////////////// Tablica (const Tablica & v) // konstruktor kopiujący T = new double [lelem = v.lelem] ; // przydzielenie pamięci int i ; for (i=0 ; i<lelem ; i++) // skopiowanie do nowej pamięci T[i]=v.T[i] ; //////////////////////////////////////////////////////////////// ; 3

Operator przypisania = Inicjalizacja: tworzenie nowego obiektu. Przypisanie: zmiana wartości istniejącego obiektu. Punkt a(1,1), b; // inicjalizacja b=a; // przypisanie Występuje podobny problem jak w przypadku kopiowania. W przypadku użycia domyślnego operatora przypisania wykonywane jest kopiowanie płytkie. class Tablica int lelem ; int *T ; public : Tablica (int n)... ; int main() Tablica a(3), b(2); Tablica a 3 10 8 5 Tablica b 2 6 8 Wykonujemy w programie instrukcję przypisania: b=a Tablica a 3 Tablica b 3 10 8 5 6 8 Wskazuje na ten sam obszar pamięci Pozostaje zajęta pamięć ze sterty, nie ma do niej dostępu Rozwiązanie: przeciążenie operatora przypisania = 4

Prototyp operatora przypisania =: MojaKlasa& operator=(const MojaKlasa &); Przykład: #include <iostream> using namespace std; class Tablica int lelem ; int *T ; public : Tablica (int n) T = new int [lelem = n] ; for (int i=0 ; i<lelem ; i++) T[i] = 0 ; ~Tablica () delete T ; // przeciążony operator przypisania Tablica& operator= (const Tablica &) ; ; /////////////////////////////////////////////////// // przeciążony operator przypisania Tablica & Tablica::operator = (const Tablica & v) if (this!= &v) // czy przypisujemy obiekt do siebie samego // 1. zwolnienie pamięci obiektu po lewej stronie = delete [ ] T ; // 2. przydzielenie na nowo pamięci T = new int [lelem = v.lelem] ; // 3. przepisanie do nowej pamięci obiektu po prawej stronie = for (int i=0 ; i<lelem ; i++) T[i] = v.t[i] ; else cout << " nic nie robimy \n" ; return * this ; //////////////////////////////////////////////////// main() Tablica a(5), b(3), c(4) ; cout << "** przypisanie a=b \n" ; a = b ; // czyli a.operator=(b) cout << "** przypisanie c=c \n" ; c = c ; // czyli c.operator=(c) cout << "** przypisanie a=b=c \n" ; a = b = c ; // czyli a.operator=(b.operator=(c)) 5

Przykład Autor- S.Prata, Szkoła programowania, język C++, rozdział 14 class Student String name; ArrayDb scores;... ; // obiekt klasy String // obiekt klasy ArrayDb Klasa String Cechy klasy: powinna umożliwiać przechowywanie napisów zmiennej długości. powinna umożliwiać dostęp do pojedynczych znaków napisu powinna umożliwiać przypisywanie jednego napisu drugiemu powinna umożliwiać porównywanie napisów // Plik string1.h -- definicja klasy #include <iostream> using namespace std; #ifndef STRING1_H_ #define STRING1_H_ class String private: char * str; // wskaźnik do napisu - alokacja pamięci // zostanie wykonana w konstruktorze int len; // długość napisu static int num_strings; // ilość obiektów - wprowadzona, aby // pokazac korzystanie ze składowej statycznej static const int CINLIM = 80; // ograniczenie długości danych wejściowych public: // konstruktory String(const char * s); // constructor String(); // default constructor String(const String &); // copy constructor ~String(); // destructor // przeciążone operatory - metody String & operator=(const String &); String & operator=(const char *); char & operator[](int i); const char & operator[](int i) const; // przeciążone operatory - funkcje zaprzyjażnione friend bool operator<(const String &st, const String &st2); friend bool operator>(const String &st1, const String &st2); friend bool operator==(const String &st, const String &st2); friend ostream & operator<<(ostream & os, const String & st); friend istream & operator>>(istream & is, String & st); // funkcje pomocnicze static int HowMany(); int length () const return len; ; #endif 6

// Plik string1.cpp -- metody klasy String #include <iostream> #include <cstring> #include "string1.h" using namespace std; // inicjalizacja składowych statycznych int String::num_strings = 0; // musi być inicjalizowana na zewnatrz // metody statyczne int String::HowMany() return num_strings; // konstruktory i destruktor // tworzenie obiektu String na podstawie napisu w stylu języka C String::String(const char * s) len = strlen(s); str = new char[len + 1]; strcpy(str, s); num_strings++; // śledzenie tworzonych obiektów // konstruktor domyślny String::String() len = 0; str = new char[1]; str[0] = '\0'; num_strings++; // śledzenie tworzonych obiektów // konstruktor kopiujący String::String(const String & st) num_strings++; len = st.len; str = new char [len + 1]; strcpy(str, st.str); // śledzenie tworzonych obiektów // destruktor String::~String() --num_strings; delete [] str; // śledzenie tworzonych obiektów 7

// przeciążone operatory -- metody // operator przypisania -- obiekt String do obiektu String String & String::operator=(const String & st) if (this == &st) return *this; delete [] str; len = st.len; str = new char[len + 1]; strcpy(str, st.str); return *this; // operator przypisania -- napis w stylu języka C do obiektu String String & String::operator=(const char * s) delete [] str; len = strlen(s); str = new char[len + 1]; strcpy(str, s); return *this; // operator [] dla obiektu nie-stałego String char & String::operator[](int i) return str[i]; // operator [] dla obiektu stałego String const char & String::operator[](int i) const return str[i]; 8

// przeciążone operatory -- funkcje zaprzyjaźnione bool operator<(const String &st1, const String &st2) return (strcmp(st1.str, st2.str) < 0); bool operator>(const String &st1, const String &st2) return st2.str < st1.str; bool operator==(const String &st1, const String &st2) return (strcmp(st1.str, st2.str) == 0); ostream & operator<<(ostream & os, const String & st) os << st.str; return os; istream & operator>>(istream & is, String & st) char temp[string::cinlim]; is.get(temp, String::CINLIM); if (is) st = temp; while (is && is.get()!= '\n') continue; return is; 9

Komentarze Konstruktory i destruktory // tworzenie obiektu String na podstawie napisu w stylu języka C String::String(const char * s) len = strlen(s); str = new char[len + 1]; strcpy(str, s); num_strings++; // śledzenie tworzonych obiektów // konstruktor domyślny String::String() len = 0; str = new char[1]; str[0] = '\0'; num_strings++; lub String::String() len = 0; str=0; num_strings++; // destruktor String::~String() --num_strings; delete [] str; // śledzenie tworzonych obiektów // śledzenie tworzonych obiektów // śledzenie tworzonych obiektów Wszystkie konstruktory muszą być zgodne z destruktorem. Ponieważ w destruktorze odwołujemy się do tablicy: delete [] str, musimy w obydwu konstruktorach używać new []. Użycie operatora delete [] w stosunku do obiektu, który nie został utworzony jako tablica obiektów jest nie zdefiniowane. Dopuszczalne jest jednak użycie wskaźnika pustego. Składowe statyczne Inicjalizacja składowej statycznej musi być dokonana na zewnątrz klasy. Instrukcję inicjalizacji należy umieścić w pliku z kodem metod. Pole statyczne może być inicjalizowane wewnątrz klasy, jeśli jest stałą (const) lub typu wyliczeniowego. Metody statyczne Metoda statyczna nie jest związana z żadnym obiektem Jedyne pola, z których korzysta to pola statyczne Przykład użycia funkcji statycznej: cout << String::HowMany()<< endl; 10

Przeciążony operator przypisania W klasie mamy dwa przeciążone operatory przypisania: String & operator=(const String &); String & operator=(const char *); Pierwszy z operatorów jest wymagany, ponieważ klasa zawiera składową dynamiczną. Drugi z operatorów został wprowadzony po to, aby można było działać bezpośrednio na napisach w stylu języka C, bez konieczności tworzenia obiektów tymczasowych. Przykład 1: Brak przeciążonego operatora = dla przypisywania napisu. String nazwisko; nazwisko="nowak"; Napis w stylu języka C musi być zamieniony na obiekt String. Wykorzystany zostanie konstruktor jednoargumentowy. Powstanie obiekt tymczasowy. Po przypisaniu zostanie usunięty. Przykład 2: Zdefiniowano przeciążony operatora String & operator=(const char *): // operator przypisania -- napis w stylu języka C do obiektu String String & String::operator=(const char * s) delete [] str; len = strlen(s); str = new char[len + 1]; strcpy(str, s); return *this; String nazwisko; nazwisko="nowak"; Użyty zostanie bezpośrednio operator przypisania. Zasada: Konwersje zdefiniowane przez użytkownika (za pomocą konstruktorów lub odpowiednich funkcji konwersji) są brane pod uwagę tylko wtedy, kiedy są niezbędne. Przeciążone operatory porównywania Dzięki temu, że są zdefiniowane jako funkcje zaprzyjaźnione, możliwe jest porównywanie obiektów String z napisami w stylu języka C 11

Przeciążony operator [] Musi umożliwiać korzystanie zarówno z obiektów nie-stałych jak i stałych. W przypadku obiektów nie-stałych: może być użyty zarówno do wyprowadzania jak i przypisywania wartości. // operator [] dla obiektu nie-stałego String // możliwy odczyt -- zapis char & String::operator[](int i) return str[i]; // operator [] dla obiektu stałego String // możliwy tylko odczyt const char & String::operator[](int i) const return str[i]; String nazwisko("nowak"); // obiekt nie jest stały const String odp("tak"); // obiekt stały // obiekt nie jest stały cout << nazwisko[0]; nazwisko[0]='n'; cin >> nazwisko[0]; // obiekt stały cout << odp[0]; 12

Klasa ArrayDb Cechy klasy: przechowywanie elementów typu double dostęp do elementów za pomocą indeksu możliwość przypisania jednej tablicy drugiej sprawdzanie czy podany indeks jest z zakresu // Plik arraydb.h -- definicja klasy ArrayDb #ifndef ARRAYDB_H_ #define ARRAYDB_H_ #include <iostream> using namespace std; class ArrayDb private: unsigned int size; // ilość elementów tablicy double * arr; // adres pierwszego elementu public: // konstruktory i destruktor ArrayDb(); explicit ArrayDb(unsigned int n, double val = 0.0); ArrayDb(const double * pn, unsigned int n); ArrayDb(const ArrayDb & a); virtual ~ArrayDb(); // metody unsigned int ArSize() const return size; // rozmiar tablicy double Average() const; // średnia wartość // przeciążone operatory -- metody double & operator[](int i); const double & operator[](int i) const; ArrayDb & operator=(const ArrayDb & a); // przeciążone operatory -- funkcje zaprzyjaźnione friend ostream & operator<<(ostream & os, const ArrayDb & a); ; #endif 13

// arraydb.cpp -- metody klasy ArrayDb #include <iostream> using namespace std; #include <cstdlib> // exit() prototype #include "arraydb.h" // konstruktory i destruktor // konstruktor domyślny ArrayDb::ArrayDb() arr = 0; size = 0; // konstruktor tworzący tablicę n-elementową, // o wartościach elementów równych val ArrayDb::ArrayDb(unsigned int n, double val) arr = new double[n]; size = n; for (int i = 0; i < size; i++) arr[i] = val; // konstruktor tworzący tablicę n-elementową, // na podstawie tablicy pn ArrayDb::ArrayDb(const double *pn, unsigned int n) arr = new double[n]; size = n; for (int i = 0; i < size; i++) arr[i] = pn[i]; // konstruktor kopiujący ArrayDb::ArrayDb(const ArrayDb & a) size = a.size; arr = new double[size]; for (int i = 0; i < size; i++) arr[i] = a.arr[i]; // destruktor ArrayDb::~ArrayDb() delete [] arr; 14

// przeciążanie operatorów -- metody // operator [] -- nie-stały obiekt double & ArrayDb::operator[](int i) if (i < 0 i >= size) cerr << "Error in array limits: " << i << " is a bad index\n"; exit(1); return arr[i]; // operator [] -- stały obiekt const double & ArrayDb::operator[](int i) const if (i < 0 i >= size) cerr << "Error in array limits: " << i << " is a bad index\n"; exit(1); return arr[i]; // operator przypisania ArrayDb & ArrayDb::operator=(const ArrayDb & a) if (this == &a) // if object assigned to self, return *this; // don't change anything delete [] arr; size = a.size; arr = new double[size]; for (int i = 0; i < size; i++) arr[i] = a.arr[i]; return *this; // przeciążanie operatorów -- funkcje zaprzyjaźnione // operator wyjścia: drukuj po pięć w wierszu ostream & operator<<(ostream & os, const ArrayDb & a) int i; for (i = 0; i < a.size; i++) os << a.arr[i] << " "; if (i % 5 == 4) os << "\n"; if (i % 5!= 0) os << "\n"; return os; 15

// metody // średnia wartość elementów tablicy double ArrayDb::Average() const double sum = 0; int i; int lim = ArSize(); for (i = 0; i < lim; i++) sum += arr[i]; if (i > 0) return sum / i; else cerr << "No entries in score array\n"; return 0; Komentarze Konstruktory i destruktor Konstruktor explicit ArrayDb(unsigned int n, double val = 0.0) może być wywołany z jednym argumentem, pełni więc dodatkowo rolę niejawnej funkcji konwersji. Za pomocą słowa explicit rezygnujemy z tej funkcji. 16

Klasa Student Cechy klasy: student jest opisywany za pomocą nazwiska i zestawu ocen // Plik studentc.h -- definicja klasy Student #ifndef STUDNTC_H_ #define STUDENTC_H_ #include <iostream> using namespace std; #include "arraydb.h" #include "string1.h" class Student private: String name; // nazwisko ArrayDb scores; // oceny public: // konstruktory i destruktor Student() : name("null Student"), scores() Student(const String & s) : name(s), scores() Student(int n) : name("nully"), scores(n) Student(const String & s, int n) : name(s), scores(n) Student(const String & s, const ArrayDb & a) : name(s), scores(a) Student(const char * str, const double * pd, int n) : name(str), scores(pd, n) ~Student() // metody double Average() const; // przeciążone operatory -- metody double & operator[](int i); const double & operator[](int i) const; // przeciążone operatory -- funkcje zaprzyjaźnione friend ostream & operator<<(ostream & os, const Student & stu); friend istream & operator>>(istream & is, Student & stu); ; #endif 17

// studentc.cpp -- metody klasy Student #include "studentc.h" // metody double Student::Average() const return scores.average(); // ArrayDb::Average() // przeciążone operatory -- metody // operator [] -- nie stałe obiekty double & Student::operator[](int i) return scores[i]; // ArrayDb::operator[]() // operator [] -- stałe obiekty const double & Student::operator[](int i) const return scores[i]; // przeciążone operatory -- funkcje zaprzyjaźnione // operator wyjścia ostream & operator<<(ostream & os, const Student & stu) os << "Scores for " << stu.name << ":\n"; os << stu.scores; return os; // operator wejścia istream & operator>>(istream & is, Student & stu) is >> stu.name; return is; 18

Komentarze Konstruktory i destruktory Przy utworzeniu obiektu zewnętrznego muszą być utworzone wszystkie obiekty wewnętrzne. W tym celu wykorzystywana jest lista inicjatorów konstruktora: podawane są nazwy obiektów i wartości początkowe. W przypadku typów wbudowanych, można je traktować tak, jakby posiadały pojedynczy konstruktor posiadający jeden argument. class Student private: String name; // nazwisko ArrayDb scores; // oceny public: // konstruktory i destruktor Student() : name("null Student"), scores() Student(const String & s) : name(s), scores() Student(int n) : name("nully"), scores(n) Student(const String & s, int n) : name(s), scores(n) Student(const String & s, const ArrayDb & a) : name(s), scores(a) Student(const char * str, const double * pd, int n) : name(str), scores(pd, n)... ; 19