plik


ÿþWykBad 7 C++: Przeci|anie operatorów, Wzorce projektowe, Zmienne dynamiczne Wskazniki i referencje, Operator przypisania Relacje, Dziedziczenie, Polimorfizm Przeci|anie operatorów Powód: Dla standardowych typów w C istnieje szereg zdefiniowanych operatorów Dla nowo tworzonych typów (klas) powinna by tak|e mo|liwo[ zdefiniowania analogicznych, intuicyjnych operatorów #include "Ulamek.h" void main() { CUlamek ulamekA(1,2), ulamekB = 3, TestUlamek.cpp(22): ulamekC; error C2676: Operator binarny '+': ulamekC = ulamekA + ulamekB; 'CUlamek' nie definiuje ulamekC *= ulamekA; takiego operatora lub konwersji int c; do operatora predefiniowanego. if(c<=0.2) { //... }; itm / MVLab (c) 2007-2011 ZBy przykBad: operatory #include "Ulamek.h" class CUlamek // ... { CUlamek Add (CUlamek U2) { private: m_iLicznik = int m_iLicznik; m_iLicznik * U2.m_iLicznik + int m_iMianownik; m_iMianownik * public: U2.m_iLicznik; CUlamek(const CUlamek& kUlamek); m_iMianownik = U2.m_iMianownik; CUlamek(int iLicznik); return *this; CUlamek(int iLicznik, }; int iMianownik); CUlamek Mul (CUlamek U2) { CUlamek Add (CUlamek U2); m_iLicznik *= U2.m_iLicznik; CUlamek Sub (CUlamek U2); m_iMianownik *= U2.m_iMianownik; CUlamek Mul (CUlamek U2); return *this; CUlamek Div (CUlamek U2); }; }; Nigdy #include "Ulamek.h" void main() w ten { CUlamek ulamekA(1,2), ulamekB(3), ulamekC; sposób ulamekC = (ulamekA.Add(ulamekB)).Mul(ulamekC); // ... }; itm / MVLab (c) 2007-2011 Przeci|anie operatorów  PrzykBad '~' #include "Ulamek.h" class CUlamek // ... { CUlamek operator~() const { private: if(!m_iMianownik) exit(1); int m_iLicznik; CUlamek tmp(m_iMianownik, m_iLicznik); int m_iMianownik; return tmp; public: }; // ... CUlamek operator*(const CUlamek& CUlamek operator~() const; aU) const { CUlamek operator*( CUlamek tmp( const CUlamek& aU) m_iLicznik*aU.m_iLicznik, const; m_iMianownik*aU.m_iMianownik); CUlamek operator=(const Culamek& aU); return tmp; // ... }; }; #include "Ulamek.h" void main() { CUlamek ulamekA(1,2), ulamekB(3); Culamek ulamekC = ~ulamekA; (ulamekA * ulamekB).Wypisz(); }; itm / MVLab (c) 2007-2011 Przeci|anie operatorów PrzykBad #include "Ulamek.h" // ... CUlamek operator~() const { if(!m_iMianownik) exit(1); CUlamek tmp (m_iLicznik, m_iMianownik); return tmp; }; CUlamek operator*(const CUlamek& aU) const { Zwracanie warto[ci CUlamek tmp( bez u|ycia referencji: m_iLicznik*aU.m_iLicznik, po przetworzeniu obiektu m_iMianownik* przez metod, aU.m_iMianownik); lokalny obiekt jest niedostpny. return tmp; Kompilator zwykle nie dostrzega }; tego problemu. itm / MVLab (c) 2007-2011 Przeci|anie operatorów PrzykBad '=' #include "Ulamek.h" class CUlamek // ... { CUlamek& operator=(const CUlamek& aU) private: { //sprawdzenei konieczne w przypadku int m_iLicznik; //komponentów dynamicznych int m_iMianownik; //np. ulamekA = ulamekA public: if(this == &aU) // ... return *this; CUlamek operator~() const; m_iLicznik = aU.m_iLicznik; CUlamek operator*( m_iMianownik = aU.m_iMianownik; const CUlamek& aU) return *this; const; CUlamek operator=(const CUlamek& aU); // ... }; Obiekt którego metoda zostaBa wywoBana #include "Ulamek.h" (a nie jego kopia!!) void main() { CUlamek ulamekA(1,2), ulamekB(3), ulamekC; ulamekC = ulamekA * (~ulamekB); ulamekC.Wypisz(); }; itm / MVLab (c) 2007-2011 Wzorce klas U|ywanie funkcji jest zale|ne od typów danych jakie one obsBuguj. Powoduje to m.in. konieczno[ ich przeci|ania. Zasadniczo ta sama funkcjonalno[ musi by czsto udostpniana dla ró|nych typów danych. Przeci|anie funkcji celem umo|liwienia wspóBpracy z ró|nymi typami powoduje: wikszy nakBad programistyczny, trudno[ci w analizie kodu, wiksze prawdopodobieDstwo bBdów, problemy z ich znalezieniem w gszczu podobnych funkcji. PrzykBadem jest bufor FIFO który dziaBa tak samo dla wszystkich mo|liwych typów danych, Rozwizaniem jest parametryzacja funkcji i klas pod wzgldem typów w postaci tzw. wzorców (szablonów -ang. templates). ’! programowanie generyczne wzorce klas itm / MVLab (c) 2007-2011 wzorce funkcji Implementacja wzorców przykBad // Wzorzec funkcji zwracajcej wiksz warto[ z dwóch podanych template<class T> T Max (T wart1, T wart2) { if(wart1>wart2) return wart1; Typ T zostanie okre[lony dalej, else return wart2; } podczas wywoBywania funkcji; // ... mo|na poda np. int -wówczas CUlamek ulamekA(2,3), ulamekB(3,4), ulamekC; ulamekC = Max(ulamekA,ulamekB); zarówno argumenty, jak int i = Max(4,5); i typ zwracany te| zostan zamienione na int // Wzorzec klasy CLista template<class T> class CLista { public: Clista(); ~Clista(); Tu równie| na tej samej void dolacz(T); zasadzie zadziaBa typ T podajOstatni(T); parametryczny T. void usunOstatni(); //... mojaLista (typu CLista<CUlamek>) }; bdzie dziaBaBa dla typu Clista Clista<CUlamek> mojaLista; CUlamek ulamekA(2,3); -wszdzie tam, mojaLista.dolacz(ulamekA); gdzie w definicji wpisany byB typ T. itm / MVLab (c) 2007-2011 Zasady postpowania z wzorcami Wzorce nie mog by (pre-)kompilowane oddzielnie. W tym celu musz istnie odpowiednie zale|no[ci, parametryzowane przez sam wzorzec -zwykle nie powoduje to bBdów. Wzorce musz by zadeklarowane i zdefiniowane w jednym pliku. S one Bczone wg zapotrzebowaD. Kompilator generuje sprecyzowane wersje klas opartych na wzorcach dopiero w przypadku odpowiedniego wywoBania. Ulamek .cpp Ulamek Kompil .obj ator Ulamek Wzorzec Linker .h .t TestUlamek Kompil TestUlamek .obj ator .exe TestUlame Wzorzec k .t .cpp itm / MVLab (c) 2007-2011 Pami dynamiczna Zmienne i tablice s statyczne i nieelastyczne -nie mo|na zmienia ich rozmiaru. Co zrobi gdy ilo[ dostpnej pamici jest w czasie programowania nieznana? np.: przetwarzanie tekstu -ile liter? obsBuga MP3 -ile piosenek? Rozwizaniem jest zastosowanie pamici dynamicznej o modyfikowalnym rozmiarze. Je[li trzeba alokuje si dodatkow przestrzeD w pamici, je[li nie -mo|na j zwolni dla innych potrzeb. Cele: efektywne gospodarowanie pamici, elastyczno[, dopasowanie do zasobów systemowych. itm / MVLab (c) 2007-2011 Pami dynamiczna w C++ Dlaczego nie tak jak w C? Wady malloc() i free() wysokie wymagania od programisty niebezpieczeDstwo naruszenia zasad ochrony pamici brak dopasowania do filozofii obiektowej Rozwizanie: operatory new() i delete() dynamiczna obsBuga pamici w C++ za pomoc operatorów new i delete zastosowanie zarówno do typów standardowych jak i do klas automatyczne (niejawne) wywoBania konstruktora w przypadku klas operatory new i delete mo|na tak|e przeBadowywa w obrbie klasy new i delete istniej zawsze razem -ka|dy dynamicznie powoBany obiekt musi by w C++ niejawnie usunity. itm / MVLab (c) 2007-2011 new i delete - przykBady brak konieczno[ci konwersji typów 4711 (typ jest ten sam) int* piMojaLiczba = new int; *piMojaLiczba = 4711; piMojaLiczba delete piMojaLiczba; dynamiczna alokacja tablicy int iRozmiar = 5; 0 11 22 33 44 int* piPole = new int [iRozmiar]; piPole for(int j=0; j<iRozmiar; j++) dynamiczna dealokacja tablicy piPole[j]=j*11; (delete bez nawiasów klamrowych delete[] piPole; spowoduje usunicie wyBcznie pierwszego elementu) CUlamek *pUlamekA = new CUlamek; wywoBanie konstruktorów CUlamek *pUlamekB = new CUlamek; CUlamek *pUlamekC = new CUlamek; L 26 L 5 L 0 pUlamekC = pUlamekB; pUlamekC M 1 M 8 M 1 //...  wisi w powietrzu delete pUlamekA; delete pUlamekB; delete pUlamekC;  wysypanie programu pUlamekA pUlamekB pUlamekC itm / MVLab (c) 2007-2011 PrzykBad: konstruktor konwertujcy // MyString.h #include "MyString.h" class CMyString #include <cstring> { #include <iostream> konstruktor public: using namespace std; korzysta z pamici CMyString(); CmyString::CMyString() { podrcznej CMyString(const char*); m_iDlugosc = 0; ~CMyString(); m_pszBuf = NULL; void pokaz(); }; private: CMyString::CMyString(const char* pszName { int m_iDlugosc; m_iDlugosc = strlen(pszName); char* m_pszBuf; m_pszBuf = new char[m_iDlugosc+1]; }; strcpy(m_pszBuf, pszName); }; mojString CmyString::~CMyString() { dealokacja delete[] m_pszBuf; w obrbie destruktora 14 }; m_iDlugosc m_pszBuf void CmyString::pokaz() { cout << "STRING-Objekt: " << m_pszBuf; }; \0 T o j e s t S t r i n g automatyczne #include "MyString.h" wywoBanie void main() { CMyString mojString("To jest String");} destruktora na koDcu bloku itm / MVLab (c) 2007-2011 PrzykBad: konstruktor konwertujcy #include "MyString.h" #include <cstring> #include <iostream> using namespace std; CmyString::CMyString() { m_iDlugosc = 0; m_pszBuf = NULL; UWAGA! }; W przypadku CMyString::CMyString(const char* pszName { pamici dynamicznej m_iDlugosc = strlen(pszName); ostro|no[ci nigdy za wiele m_pszBuf = new char[m_iDlugosc+1]; strcpy(m_pszBuf, pszName); }; CmyString::~CMyString() { if(m_pszBuf!=NULL) delete[] m_pszBuf; delete[] m_pszBuf; }; m_pszBuf = NULL; void CmyString::pokaz() { cout << "STRING-Objekt: " << m_pszBuf; }; #include "MyString.h" void main() { CMyString mojString("To jest String");} itm / MVLab (c) 2007-2011 Dynamiczne komponenty i kopie PBaskie kopie Standardowo kopiowanie ani przypisanie nie powiela zawarto[ci dynamicznej, przez co dynamiczna zawarto[ staje si przynale|na do wielu obiektów Wa|ne w przypadku konstruktorów kopiujcych oraz operatorów przypisania. String4 String3 String2 String1 CMyString String1("Pierwszy String"); //Niejawne wyw. konstr. kopujcego: 15 15 15 15 CMyString String2 = String1; CMyString String3; //Niejawne wyw. operat. przypisania: String3 = String1; //String4 pozostawiony "w powietrzu": CMyString String4("Czwarty String"); String4 = String1; Zamiany dokonane w którymkolwiek stringu maj wpByw na inne! \  Wisi C z w a r t y S t r i n g \ 0 w powietrzu! P i e r w s z y S t r i n g 0 itm / MVLab (c) 2007-2011 Dynamiczne komponenty i kopie GBbokie kopie Dla ka|dej operacji kopiowania zostaje zaalokowana pami do której kopiowana jest ta sama zawarto[, jednak w innym, indywidualnie przydzielonym miejscu w pamici. String4 String3 String2 String1 CMyString String1("Pierwszy String"); 15 15 15 15 //Niejawne wyw. konstr. kopujcego: CMyString String2 = String1; CMyString String3; //Niejawne wyw. operat. przypisania: String3 = String1; //Przygotowanie pamici dla String4 CMyString String4("Czwarty String"); P i e r w s z y S t r i n g \0 String4 = String1; P i e r w s z y S t r i n g \0 P i e r w s z y S t r i n g \0 C z w a r t y S t r i n g \0 Usunity P i e r w s z y S t r i n g \0 itm / MVLab (c) 2007-2011 PrzykBad: gBbokie kopiowanie wBasny konstruktor kopiujcy i przeci|enie operat. // MyString.h CMyString::CMyString(const CMyString& class CMyString argString) { { public: m_iDlugosc = argString.m_iDlugosc; //... if(m_iDlugosc == 0) m_pszBuf = NULL; CmyString(const else { CMyString&); m_pszBuf = new char[m_iDlugosc+1]; CMyString& operator= strcpy(m_pszBuf, argString.m_pszBuf); (const CMyString&); } private: } int m_iDlugosc; CMyString& CMyString::operator= (const char* m_pszBuf; CMyString& argString) }; { if(this == &argString) return *this; m_iDlugosc = argString.m_iDlugosc; if(m_pszBuf != NULL) delete[] m_pszBuf; zabezpieczenie if(m_iLaenge == 0) m_pszBuf = NULL; przed else { samozniszczeniem m_pszBuf = new char[m_iDlugosc+1]; strcpy(m_pszBuf, einString.m_pszBuf); } return *this; } itm / MVLab (c) 2007-2011 Podsumowanie rozdz. 4.3 obsBuga pamici jawne i niejawne statyczna/dynamiczna wywoBania Metody " Konstruktory " Inicjalizacja podczas (standardowe, kopiujce, " tworzenia instancji przeci|anie pBytkie " konwertujce, inne) " usuwanie obiektów wzorce i gBbokie " Destruktory kopiowanie, gBboki " operatory " dopasowywanie funkcji operator " pozostaBe funkcje " obsBuga innych obiektów przypisania przestrzenie nazw zwracanie warto[ci typ metody przez referencj (czy zmienia stan?) itm / MVLab (c) 2007-2011 Rozró|nianie wskazników i referencji CUlamek* p_ulamek = &ulamek1; Ulamek1 Ulamek2 0x0011fec1 0x0011fec9 zwykle u|ycie w C L 11 L 5 Wskaznik M 45 M 12 " zmienna która zawiera adres obszaru pamici " mo|na wskazywa na: zmienne, obiekty, obszary kodu " mo|liwa warto[ NULL oraz wkazniki do niesprecyzowanego typu p_ulamek " arytmetyka wskazników (np. dostp do zmiennych) CUlamek* p_ulamek = new CUlamek; int *p_iPole = new int[40]; zwykBe u|ycie w C++ dowolna pozycja Dynamiczna obsBuga pamici za znaku wskaznika pomoc new i delete zabezpieczenie przed u|yciem if(p_ulamek!=NULL) //p_iPole!=NULL; operatora delete delete p_ulamek; //delete[] p_iPole; na rzecz wskaznika do NULL p_ulamek=NULL; //p_iPole=NULL; itm / MVLab (c) 2007-2011 Rozró|nienie wskazników i referencji Referencje (nowy element skBadni C++) L 0 M 1 Referencje dostarczaj odno[ników do obiektów Analogicznie do wskazników: odno[nik do adresu w pamici W C++ ka|dy obiekt automatycznie dostaje swoj referencj ALE: pomimo takiej samej pisowni CUlamek ulamek1(1,2); operator referencji jest Batwo odró|nialny //pobranie referencji od operatora adresu CUlamek& aliasulamka = ulamek1; Op. referencji jest u|ywany zwykle & operator+(const CUlamek& n_ulamek){ w deklaracjach  zaraz za typem danych this->m_iz=m_iz+n_ulamek.m_iz; Op. adresu u|ywa si przy operacjach }; na zmiennych i stoi zwykle przed ich nazwami Zastosowanie referencji jest, w porównaniu do wskazników, pewniejsze, poniewa| wskazuj zawsze jeden, dokBadnie zdefiniowany obiekt, Brak arytmetyki  referencje nie mog by np. inkrementowane Mechanizm przekazywania parametrów call-by-reference Dostpne jak  normalne zmienne itm / MVLab (c) 2007-2011 DokBadniej o operatorze przypisania I CUlamek ulamek1(4,6); suma ulamek1 ulamek2 CUlamek ulamek2(5); //pobranie referencji L 9 L 4 L 5 = + CUlamek suma = ulamek1 + ulamek2; M 7 M 6 M 1 suma.wyswietl(); W przypadku operatorów Sumowanie atrybutów dwóch obiektów CUlamek; warto[ lewa i prawa musz Wynik typu CUlamek; by identyczne Niejawne wywoBanie konstruktora kopiujcego; Dlaczego nie mo|na zastosowa zwracania warto[ci przez referencj? Lokalne kopie obiektów zostan na koDcu dziaBania funkcji usunite Wobec tego tak|e referencja& CUlamek CUlamek::operator+ (const CUlamek &n_ulamek) { CUlamek tmp( (this->m_iLicznik+n_ulamek.m_iLicznik), (this->m_iMianownik+n_ulamek.m_iMianownik)); return tmp; } itm / MVLab (c) 2007-2011 DokBadniej o operatorze przypisania I CUlamek ulamek1(4,6); suma ulamek1 ulamek2 CUlamek ulamek2(5); //pobranie referencji L 9 L 4 L 5 = + CUlamek suma = ulamek1 + ulamek2; M 7 M 6 M 1 suma.wyswietl(); W przypadku operatorów Sumowanie atrybutów dwóch obiektów CUlamek; warto[ lewa i prawa musz by identyczne Wynik typu CUlamek; Niejawne wywoBanie konstruktora kopiujcego; Dlaczego nie mo|na zastosowa zwracania warto[ci przez referencj? Lokalne kopie obiektów zostan na koDcu dziaBania funkcji usunite Wobec tego tak|e referencja& CUlamek& CUlamek::operator+ (const CUlamek &n_ulamek) { CUlamek tmp( (this->m_iLicznik+n_ulamek.m_iLicznik), (this->m_iMianownik+n_ulamek.m_iMianownik)); return tmp; } itm / MVLab (c) 2007-2011 DokBadniej o operatorze przypisania II Obydwa obiekty istniej  konieczne przypisanie Musi by zgodno[ typów CUlamek ulamek1(4,6); Przeci|ony operator "=" (gBbokie kopiowanie) CUlamek ulamek2(17,4); ulamek1 = ulamek2; ulamek1.wyswietl(); 3 mo|liwo[ci implementacji CUlamek CUlamek::operator= (const CUlamek &n_ulamek) { if(this==&n_ulamek) //must avoid self destruction //... cout<<"assignment operator called"; this->m_iMianownik=n_ulamek.m_iMianownik; this->m_iLicznik=n_ulamek.m_iLicznik; CUlamek temp(this->m_iLicznik,this->m_iMianownik); cout<<"assignment operator finished"; return temp; } itm / MVLab (c) 2007-2011 DokBadniej o operatorze przypisania II Obydwa obiekty istniej  konieczne przypisanie Musi by zgodno[ typów CUlamek ulamek1(4,6); Przeci|ony operator "=" (gBbokie kopiowanie) CUlamek ulamek2(17,4); ulamek1 = ulamek2; ulamek1.wyswietl(); 3 mo|liwo[ci implementacji CUlamek CUlamek::operator= (const CUlamek &n_ulamek) { if(this==&n_ulamek) //must avoid self destruction //... cout<<"assignment operator called"; this->m_iMianownik=n_ulamek.m_iMianownik; this->m_iLicznik=n_ulamek.m_iLicznik; cout<<"assignment operator finished"; return CUlamek (this->m_iLicznik, this->m_iMianownik); } itm / MVLab (c) 2007-2011 DokBadniej o operatorze przypisania II Obydwa obiekty istniej  konieczne przypisanie Musi by zgodno[ typów CUlamek ulamek1(4,6); Przeci|ony operator "=" (gBbokie kopiowanie) CUlamek ulamek2(17,4); ulamek1 = ulamek2; ulamek1.wyswietl(); 3 mo|liwo[ci implementacji CUlamek& CUlamek::operator =(const CUlamek& n_Ulamek) { if(this == &n_Ulamek) //must avoid self destruction return *this; cout <<  assignment operator called ; this->m_iLicznik = n_Ulamek.m_iLicznik; this->m_iMianownik = n_Ulamek.m_iMianownik; cout << "\nassignment operator finished\n"; return *this; // wszystkie kopie zachowane } itm / MVLab (c) 2007-2011 Co ju| byBo (w rozdz. 3 i 4)? To ju| potrafimy: implementacja klas niezale|nie od ich pózniejszego u|ycia rozdziaB na deklaracje (header) oraz definicje i u|ycie (implementacja) stosowanie zasady information-hiding implementacja operacji w postaci Rodzic metod i operatorów To musimy sobie przypomnie: krok 1.: deklaracja i implementacja klas, Potomek 1 Potomek 2 krok 2.: zastosowanie w konkretnym przypadku Teraz chodzi nam o: implementacja zale|no[ci pomidzy klasami. itm / MVLab (c) 2007-2011 4.4 Zale|no[ci midzy klasami 4.4.1 Relacje wspóBpracy Kompozycje Agregacje Asocjacje 4.3.2 Relacje dziedziczenia Dziedziczenie proste Dziedziczenie zBo|one itm / MVLab (c) 2007-2011 itm / MVLab (c) 2007-2008 Relacje wspóBpracy (asocjacje) CaBo[ Cz[ zale|na Asocjacja, to rodzaj zale|no[ci 1 * pomidzy klasami. Opisuje wspóln semantyk i struktur CaBo[ Cz[ zbioru powizaD midzy obiektami. 0..1 * Instancja asocjacji (poBczenie midzy obiektami klasy) Klasa 1 Klasa 2 okre[la si jako link. Cechy rozró|niajce: -pracodawca -pracobiorca Firma Pracownik wg typu zatrudniony 1 * -nazwa -nazwisko kompozycja -adres -nr_umowy agregacja (prosta) asocjacja Rachunek Adres X ma * 1 wg kierunkowo[ci -warto[ -ulica -adres -kod_poczt wg wielokrotno[ci itm / MVLab (c) 2007-2011 Kompozycja WBa[ciwo[ci: CaBo[ Cz[ zale|na Kryterium: zachowanie danych 1 * Kapsulacja cz[ci skBadowych Zale|no[ czasu |ycia // PrzykBad kompozycji // PrzykBad kompozycji //Calosc.h //Calosc.h class CCalosc { #include "Calosc.h" private: CCalosc::CCzesc::CCzesc() { int m_wlasciwosc; m_a=0; m_b=0; class CCzesc { }; int m_a; void CCalosc::CCzesc::test() { int m_b; m_a=1; m_b=1; public: } CCzesc(); void test(); Zagnie|d|one deklaracje } m_drugaWlasciwosc; klas i zmiennych wewntrz }; klasy zawierajcej itm / MVLab (c) 2007-2011 Agregacja CaBo[ 1 0..1 WBa[ciwo[ci: Cz[ Kryterim: zachowanie danych * CaBo[ 2 Klasy posBuguj si klasami 0..1 Zale|no[ skBada-si-z& // PrzykBad agregacja // PrzykBad agregacji // Osoba.h // main.cpp #include "MyString.h" #include "Calosc.h" class COsoba { void main() { private: COsoba Osoba1; CMyString m_imie; //... CMyString m_nazwisko; } public: //... }; Klasa COsoba posBuguje si obiektami innej klasy jako wBa[ciwo[ciami. itm / MVLab (c) 2007-2011 Agregacja: PowoBywanie obiektów Krok 1: Alokacja pamici Krok 2: Konstruktor // PrzykBad agregacji domy[lny dla imi // main.cpp #include "Calosc.h" Osoba1 Osoba1 void main() { imi nazwisko imi nazwisko COsoba Osoba1; //... ??? ??? 0 ??? } ??? ??? NULL ??? WywoBanie konstruktorów domy[lnych komponentów Krok 3: Konstruktor Krok 4: Konstruktor domy[lny dla nazwisko domy[lny dla klasy zagregowanych (w COsoba kolejno[ci deklaracji)  krok 2. i 3. nastpuje przed Osoba1 Osoba1 wywoBaniem konstruktora imi nazwisko imi nazwisko klasy. 0 0 0 0 NULL NULL NULL NULL itm / MVLab (c) 2007-2011 Lista inicjalizacyjna Klasy bez konstruktorów domy[lnych nie mog by agregowane przez inne klasy (z wyjtkiem tych gdzie s zdefiniowane inne konstruktory, ale nie domy[lny. WywoBanie konstruktora domy[lnego elementu agregowanego jest bezsensowne, je[li konstruktor obiektu agregujcego nadpisze dane. // Osoba.cpp (ZAA WERSJA!) // Osoba.h #include "Osoba.h" #include "MyString.h" COsoba::COsoba(CMyString& imie, Class COsoba { CMyString& nazwisko) { public: m_nazwisko = nazwisko; COsoba(CMyString& imie, m_imie = imie; CMyString& nazwisko); ja }; //... imi nazwisko void main() { Krok 4: Konstruktor CMyString vn = "Marcin"; 6 6 gBówny nadpisuje ewent. CMyString nn = "Wróbel"; warto[ci wpisane przez COsoba ja(vn,nn); konstruktor domy[lny. //... Marcin Wróbel itm / MVLab (c) 2007-2011 Lista inicjalizacyjna WBa[ciwo[ci: Pozwalaj konstruktorom u|ywanym do inicjalizacji komponentów przekazywa argumenty przez warto[ Mog zosta u|yte tylko dla konstruktorów SkBadnia: S wypisywane za list argumentów funkcji, po dwukropku SkBadaj si z listy wyra|eD rozdzielanych przecinkiem, w postaci komponent(argument); // Osoba.cpp (wersja poprawiona) #include "Osoba.h" COsoba::COsoba(CMyString& imie, CMyString& nazwisko): m_imie(imie), m_nazwisko(nazwisko) Dziki takiej li[cie { // Nic wicej nie trzeba robi! }; nie bd uruchamiane domy[lne konstruktory klas zagregowanych, lecz konstruktory kopiujce. itm / MVLab (c) 2007-2011 (Proste) Asocjacje WBa[ciwo[ci: Kryterim: zachowanie danych Rachunek Adres X ma Obiekty ró|nych klas  znaj si * 1 -warto[ -ulica nawzajem -adres -kod_poczt Umo|liwienie wywoBania metod obiektów innych klas Nie umiem Cechy: kierunkowo[ i wielokrotno[ pBywa, nie umiem pBywa!!! Pomocy!! -Ju| nie mog.... A ja chodzi, a mimo to nie dr uwzgldnienie wszystkich aspektów si jak gBupi na wyszBoby daleko poza nasze ramy caB okolic... ograniczamy si wyBcznie na asocjacjach 1:1, jedno- i dwukierunkowych. itm / MVLab (c) 2007-2011 Asocjacja - przykBad Sytuacja: Projektowana jest aplikacja do Arytmetyka Ulamek X obliczeD arytmetycznych, która zna 0 1 -licznik ma korzysta z obiektów klasy -mianownik uBamek.  Zapoznanie tych dwóch klas // PrzykBad asocjacji ze sob powinno si odbywa // Arytm.h w konstruktorze której[ z klas #include "Ulamek.h" programu obliczeniowego. class CArytm { private: // PrzykBad asocjacji CUlamek* p_ulamek; // main.cpp public: #include "Arytm.h" CArytm(); void main() { CArytm(CUlamek* p_ulamek); CUlamek ulamek1(2,3); //... CArytm Ar1(&ulamek1); //... Asocjacja przez }  Zapoznanie wskaznik na obiekt zewntrzny itm / MVLab (c) 2007-2011 Zaprzyjaznienia (friend) Wszystkie dotychczas omówione zale|no[ci wymagaj CUlamek ulamek1(5,7); dostpu jednej klasy do metod drugiej. Co jednak, gdy Culamek ulamek2; nie mo|na tego zrealizowa int liczba = 3; PrzykBady: Operator dodawania zmiennej int i obiektu klasy CUlamek, gdy int jest pierwszym operandem wymaga przeci|enia operatora+ dla typu int. ulamek2=liczba+ulamek1; Wyj[cie obiektu klasy CUlamek na strumieD cout za pomoc standardowego operatora << wymaga jego przeci|enia w klasie ostream (z niej pochodzi obiekt cout). cout<<"Wynik: "<<ulamek2; Rozwizanie: Globalne definicje przeBadowywanych funkcji jako funkcji zaprzyjaznionych, oznaczonych sBowem kluczowym friend, dziki czemu mog one mie dostp do prywatnych skBadników klas z którymi s zaprzyjaznione. ALE: Ka|dy kij ma dwa koDce! -kolizja z zasad information-hiding. itm / MVLab (c) 2007-2011 Zaprzyjaznienia - przykBad Sytuacja: chcemy umo|liwi operacj jak na przykBadzie poni|ej: cout << "Wartosc ulamka: "<< ulamek1 << endl; W ten sposób funkcja // CUlamek.h uzyska dostp do prywatnych class Culamek { skBadników klasy CUlamek. private: int m_iLicznik, m_iMianownik; friend ostream& operator<<(ostream&, const CUlamek&); public: Globalne przeci|enie operatora <<. //... Zostanie przyjte przez system } je[li nie znajdzie si |aden pasujcy operator w klasie ostream. // main.cpp (Funkcje globalne) ostream& operator<<(ostream& str, const CUlamek& ulamek) { str << ulamek.m_iLicznik << "/" << ulamek.m_iMianownik; return str; } Dostp do prywatnego //... skBadnika klasy CUlamek. void main() //... itm / MVLab (c) 2007-2011 Dziedziczenie Dziedziczenie podklasy (tak|e klasy cz[ciowe, klasy wyprowadzone i podklasy) dziedzicz wszystkie wBa[ciwo[ci i metody swoich klas bazowych. mog posiada wBasne -niezale|ne od klas bazowych oraz innych klas potomnych (rodzeDstwa) skBadniki oraz modyfikowa metody odziedziczone. Rodzic zasada ponownego wykorzystania kodu. Problemy dziedziczenie proste vs. dziedziczenie zBo|one polimorfizm vs. funkcje wirtualne. Potomek itm / MVLab (c) 2007-2011 Dziedziczenie proste Specjalizacja klasy bazowej Ulamek PrzykBad: klasa CUlamekDzies specjalizujcy -Licznik: int -Mianownik: int klas CUlamek o mo|liwo[ definiowania dokBadno[ci. Wyra|enie definiujce dziedziczenie UlamekDzies -Dokladnosc: int // PrzykBad dziedziczenia // UlamekDzies.h #include "Ulamek.h" class CUlamekDzies: public CUlamek { private: Nowy atrybut int m_iDokladnosc; public: Nowy konstruktor CUlamekDzies(int L, int M, int D); (trójparametrowy) void pokaz() const; Przedefiniowanie } (dopasowanie) metody itm / MVLab (c) 2007-2011 Dziedziczenie proste -przykBad Poni|sze przykBady nie nale| do dobrego stylu programistycznego i s przytoczone w tej postaci tylko dla jasno[ci kodu. // PrzykBad dziedziczenia // PrzykBad dziedziczenia // UlamekDzies.h // UlamekDzies.cpp #include "Ulamek.h" #include "Ulamek.h" class CUlamekDzies: #include <math.h> public CUlamek CUlamekDzies::CUlamekDzies { (int iL, int iM, int iD) { private: this->Zmien(pow(10,iD)*iL/iM, int m_iDokladnosc; pow(10,iD)); public: m_iDokladnosc=iD; CUlamekDzies } (int L, int M, int D); void CUlamekDzies::pokaz() const { void pokaz() const; CUlamek::pokaz(); } cout<<"Dokladnosc: "<<m_iDokladnosc; } #include "UlamekDzies.h" void main() { Jawne wywoBanie CUlamekDzies mojUlamekDzies(1,3,3); metody klasy zewntrznej mojUlamekDzies.pokaz(); } Odziedziczona metoda itm / MVLab (c) 2007-2011 Polimorfizm dziki polimorfizmowi mo|liwe jest wywoBywanie metody obiektu bez odgórnej wiedzy jakiej jest on klasy -system sam j okre[li i spowoduje |e na pewno zareaguje on na swój specyficzny sposób dziedziczenie powoduje zachowania polimorficzne #include "UlamekDzies.h" void main() { OK. CUlamekDzies mojUlamekDzies(1,3,3); CUlamek mojUlamek(2,5); CUlamekDzies CUlamek *wynikUlamkowy; jest przecie| równie| CUlamek //Przypadek 1 wynikUlamkowy = &mojUlamek; wynikUlamkowy->pokaz(); //Przypadek 2 Niestety wynikUlamkowy = &mojUlamekDzies; nie poka|e tego wynikUlamkowy->pokaz(); co chcemy } itm / MVLab (c) 2007-2011 Polimorfizm i wirtualno[ // Ulamek.h #include "UlamekDzies.h" #include <iostream> void main() { using namespace std; CUlamekDzies mojUlamekDzies(1,3,3); class CUlamek { CUlamek mojUlamek(2,5); private: CUlamek *wynikUlamkowy; int m_iLicznik; int m_iMianownik; //Przypadek 1 public: wynikUlamkowy = &mojUlamek; virtual void pokaz() const; wynikUlamkowy->pokaz(); virtual ~CUlamek(); //... //Przypadek 2 }; wynikUlamkowy = &mojUlamekDzies; wynikUlamkowy->pokaz(); } SBowo kluczowe virtual w pliku nagBówkowym mówi o tym, |e metoda klasy potomnej mo|e zosta nadpisana. Dopasowanie metod w czasie dziaBania Szczególnie wa|ne: wirtualny destruktor!! przez tzw. wirtualn tablic metod. Zalety: zachowuje si tak jak chcemy Wady: utrata efektywno[ci. itm / MVLab (c) 2007-2011 PrzykBad zastosowania: Zdarzenia DostawcaZdarzenia DostawcaZdarzenia -Handler: HandlZdarz + ~DostZdarz() + DostZdarz(in Handl1: HandlZdarz&) HandlerZdarzenia DataChangedHandler -Ilosc: int -Abonamenty: wektor<AbonentZdarz*> + HandlZdarz() + nowyAbonent(in Abnt: AbonentZdarz&) + usunAbonenta(in Abnt: AbonentZdarz&) + odklejOdZdarz(in Dost: DostZdarz&) AbonentZdarzenia Wizualizacja + OnZdarzenie(in Dost: DostZdarz&): bool + OnZdarzenie(in Dost: DostZdarz&): bool itm / MVLab (c) 2007-2011 Powtórka i podsumowanie rozdz. 4.4 Zaprzyjaznienia listy inicjalizacyjne (friends) Zale|no[ci midzy klasami " Kompozycje " Klasy u|ywaj klas " Agregacje " Zale|no[  has-a " Asocjacje " Inne zale|no[ci " Dziedziczenie proste " Zale|no[  is-a " (Dziedziczenie " Dopasowywanie i wielokrotne) rozszerzanie dziedziczonej funkcjonalno[ci wirtualno[ polimorfizm itm / MVLab (c) 2007-2011 Czego zabrakBo - rozdziaB 4.5 4.1 Zanim rozpoczniemy implementacj... 4.2 Pierwsze kroki w kierunku (w nastpnym semestrze) programowania w C++ Kiedy przewiczymy podstawy 4.3 Klasy  rosn ... bdziemy programowa pierwsze aplikacje obiektpwe w c++ 4.4 Zale|no[ci pomidzy klasami 4.5 Implementacja rozwizaD itm / MVLab (c) 2007-2011

Wyszukiwarka