180 likes | 359 Views
Programowanie obiektowe III rok EiT. dr inż. Jerzy Kotowski Wykład VII. Program wykładu. Źródła podejścia obiektowego Podstawy metody PRINCE - PR ojects I n C ontrolled E nvironment Podstawy metody LFA - L ogical F ramework A pproach , składanie wniosków o grant
E N D
Programowanie obiektoweIII rok EiT dr inż. Jerzy Kotowski Wykład VII
Program wykładu • Źródła podejścia obiektowego • Podstawy metody PRINCE -PRojects In Controlled Environment • Podstawy metody LFA -Logical Framework Approach, składanie wniosków o grant • Język C++ - gadżety języka, polimorfizm, klasy, dziedziczenie • Gadżety języka C++ • Przykład problemu • Podstawy języka JAVA • Klasówka
Literatura • C++ for C programmers, Ira Pohl, The Benjamin/Cummings Publishing Company, Inc. • Symfonia C++, Jerzy Grębosz, Oficyna Kallimach, Kraków 1999
Poprawiona klasa String class String // Część 1/2 { char *s; // nowy element int len; public: String(int n) { s=new char[n+1]; len=n; } String(char *p) { len=strlen(p); s=new char[len+1]; strcpy(s,p); } String() { len=255; s=new char[255];} //polimorfizm konstruktora ~String() { delete s;} // destruktor void assign(char *st) { strcpy(s,st); len=(int)strlen(st); } int lenght() { return(len); } void print() { cout << s << "\nLenght: " << len << "\n\n";} friend String operator +(String& a, String& b); }; • Klasa String została wyposażona w 3 konstruktory i destruktor • Konstruktory wykorzystują operator new • Destruktor wykorzystuje operator delete • Zniknęła linia z deklaracją const int max_len • W klasie nie ma pola roboczego char s[max_len], jest tylko wskaźnik char *s • Interface klasy pozostał niezmieniony
Komentarz do programu • new jest nowym operatorem języka C++. • Jest to operator jednoargumentowy. • Jego argumentem jest nazwa typu. Może być ona użyta w kontekście z definicją tablicy: s=new char[n+1] • Operator new zwraca adres do pamięci. • Obszar pamięci zajęty przy pomocy operatora new nie jest automatycznie zwalniany po wyjściu z bloku. Do zwolnienia tego obszaru pamięci jest potrzebny destruktor i operator delete. • Destruktor ma taką samą nazwę jak definiowana klasa. Jest poprzedzony znakiem ~ (tilde):~String() { delete s;} • Z reguły mamy do czynienia z polimorfizmem konstruktora. W przykładzie mamy do czynienia z trzema konstruktorami. • Konstruktory mogą być przeciążane a destruktor nie. • Konstruktory i destruktor nie zwracają nawet nic (void).
Śmiertelne niebezpieczeństwo..\..\Visual Studio Projects\test0\test0.sln void main(void) // Część 2/2 { String one, two("Gosia"); one=two; one.print(); two.print(); cout<<"Podstawiamy do two"<<endl; two.assign("Ela"); one.print(); two.print(); cout<<"Gdzie jest Gosia?"<<endl; getch(); } • Zbiór dyskowy: String II.cpp • Poprawiona klasa String może doprowadzić do wybuchu III wojny światowej • W klasie brakuje przeciążenia operatora przypisania i jawnego konstruktora kopiującego • Bez konstruktora kopiującego nie będzie działać prawidłowo przeciążony operator dodawania • A przykład jest z całkiem dobrej książki…
Prototypy funkcji • W odróżnieniu od klasycznego C prototypy funkcji w C++ informują jednoznacznie kompilator o typie i liczbie argumentów. Lista argumentów może opcjonalnie zawierać nazwy zmiennych • int Ala() • W C nic nie wiemy o argumentach funkcji Ala • W c++ funkcja Ala nie ma argumentów:int Ala()Ala()Ala(void)int Ala(void) • W C++ wartość argumentu jest zawsze przekształcana do typu jakiego spodziewa się wywoływana funkcja.
Unikanie preprocesora • W C dyrektywa define ma 3 znaczenia#define Kwadrat #ifdef Kwadrat#define Kwadrat 10 y=Kwadrat;#define Kwadrat(x) ((x)*(x)) y=Kwadrat(2+v); • inlinei constsą używane w celu unikania define. • preprocesor nie zna !! składni języka C. • słowo kluczowe inlinejest życzeniem kierowanym do kompilatora aby funkcję skompilował jako macro. Kompilator może to życzenie zignorować. • Modyfikator const jest specyfikatorem typu (jak extern itp.) Bez typu przez domniemanie oznacza int. Zmienna zadeklarowana jako constnie może zmieniać swojej wartości. • Zmienna ze specyfikatorem constmoże być używana jako literał, to znaczy na przykład jako rozmiar tablicy. • Obiekt constnie może być używany jako lewy argument operatora podstawiania - nie jest to lvalue. lvalue jest wyrażeniem, z którym wiąże się adres w pamięci pod którym można coś przechować. • zmienna constmoże być inicjalizowana.
Przykład ..\..\Visual Studio Projects\test0\test0.sln // circle.cpp constfloat ppi=3.14159; constint True=1; inlinefloat circum(float rad) {return (ppi*2*rad);} inlinefloat area(float rad) {return (ppi*rad*rad);} void main(void) { float r; while(True) { cout<<"\Enter radius: "; cin>>r; if(!r) break; cout<<"Area is "<<area(r); cout<<"\nCircumference is "<<circum(r)<<"\n\n"; }; }
const - przykłady • const int M_size=20;na przykład do deklaracji tablicy • const* p=&M_size;wskaźnik do stałej, przez domniemanie typu int • char* const s="abcde"; wskaźnik typu const do zmiennej typu char • const* int const cp=&M_size;stały wskaźnik do stałej • Ogólne zasady: • const type* identifier- wskaźnik do stałej • type* const identifier- wskaźnik typuconst • Czyli stałe jest to czego bliżej jest słowo const
Typ wyliczeniowy enum • enum types zostały dodane do C w 1980 roku • Definicja typu wyliczeniowego:enum nazwa_typu {lista wyliczeniowa}; • Przykład 1:enum week_day {Sun, Mon, Tue, Wed, Thu, Fri, Sat};week_day birth=Sun;Wartości: 0,1,2,3,4,5,6 • Przykład 2:enum week_day {Sun=-1, Mon, Tue=5, Wed, Thu, Fri, Sat};Wartości: -1,0,5,6,7,8,9 • Przykład 3:enum boolean {False, True};boolean pytanie=True; • Typ wyliczeniowy stosujemy wtedy, gdy interesuje nas bardziej logiczna interpretacja zmiennej niż jej wartość liczbowa. • Stosowanie typów wyliczeniowych pomaga wykryć kompilatorowi błąd w kodzie źródłowym naszego programu. Ma to miejsce na przykład wtedy gdy jakaś funkcja spodziewa się jako jednego ze swoich argumentów określonego typu wyliczeniowego a my podajemy coś innego. Jest to błąd kompilacji.
enum – przykład ..\..\Visual Studio Projects\test0\test0.sln • Zbiór dyskowy: Talia kart.cpp • Tasujemy talię kart do brydża • card deck[52]; - tablica kart do brydża • void shuffle(card d[]) - argumentem jest wskaźnik do obiektu typu card czyli do pierwszego elementu tablicy deck • filozofia procedury: na i-tym miejscu ustawiamy k-tą kartę, gdzie k jest losowane. • void pr_card(card& cd)- przekazanie argumentu przez referencję.
Klasa register i modyfikator volatile • Użycie:register int a;volatile float b; • Są to modyfikatory (J. Grębosz) • Ogólnie: C++ zna następujące klasyauto register static extern • register jest to prośba do kompilatora aby w miarę możliwości trzymał taki obiekt blisko, a najlepiej w jakimś rejestrze procesora. • Nie można po utworzeniu takiego obiektu szukać jego adresu. • Modyfikator volatile (ulotny) oznacza, że obiekt tak określony może zmieniać się poza kontrolą kompilatora. • Przykład: volatile float temperatura;
Operator zakresu ..\..\Visual Studio Projects\test0\test0.sln • W C++ te same nazwy mogą oznaczać różne obiekty. Wykorzystanie nazwy w wewnętrznym bloku przesłania jej zewnętrzne wykorzystanie. • C++ posiada scope resolution operator::, którego zadaniem jest odsłanianie przysłoniętych identyfikatorów globalnych. • Priorytet 17 • Ten operator łamie modularność programu i nie należy korzystać z niego zbyt często bo nie po to wymyślono C++. • Zbiór:op_zakresu.cpp int i=1; void main(void) { int i=2; //redeklaracja { cout<<"Enter inner block\n"; int n=i; int i=3; // kolejna redeklaracja cout<<i<<" i <> :: i "<<::i<<"\n"; cout<<"n = "<<n<<"\n"; } cout<<"Enter outer block\n"; cout<<i<<" i <> :: i "<<::i<<"\n"; getch(); }
Referencje • Referencja == nazwa zastępcza == alias == ksywa • C++ pozwala na deklaracje typu reference to. Mają one postać: type& identifier=object. • Taka deklaracja deklaruje identyfikator , który jest alternatywną nazwą do obiektu wyspecyfikowanego w deklaracji. • Przykłady: int n;int& nn = n; nn jest alternatywną nazwą do ndouble a[10];double& last = a[9];char& new_line = '\n'; • Deklaracja reference to nie może być odwołana. • Głównym zastosowaniem reference to jest bezpośrednie przekazywanie argumentów funkcjom. Nazywa się to call-by reference.
Referencje c.d. ..\..\Visual Studio Projects\test0\test0.sln // referencje.cpp int greater(int& a,int& b) { if(a>b) { int temp=a; a=b; b=temp; return(1); } elsereturn(0); } void main(void) { int i,j; cout <<"Pierwsza liczba calkowita: "; cin >> i; cout <<"Druga liczba calkowita: "; cin >> j; cout << "\nWprowadzone liczby: " << i << " " << j; if(greater(i,j)) // w klasycznym C trzeba tu podać adresy!! { cout<<"\nLiczby zostaly zamienione miejscami."; cout << "\nWprowadzone liczby po zamianie: " << i << " " << j; } else cout<<"\nLiczby nie zostaly zamienione miejscami."; getch(); }
Argumenty domniemane • Default arguments • Argumenty domniemane określa się w deklaracji funkcji czyli tam, gdzie kompilator dowiaduje się o interfejsie funkcji ze środowiskiem • Argumenty domniemane można opuszczać od końca • W przykładzie definicja funkcji jest równocześnie deklaracją int mult(int n,int k=2,int a=1) { if(k==2)return(a*n*n); elsereturn(mult(n,k-1,a)*n); } • Funkcja mult zwracaa*nk • Przykłady użycia:mult(5); // 52mult(5,4); // 54mult(5,3,2); // 2*53 • Zastosowanie przy tworzeniu konstruktorów
Nienazwany argument • Na liście argumentów w definicji funkcji pojawia się argument bez nazwy. • Przykład:void sound(int){…} • Oznacza to, że wewnątrz definicji ten argument się nie pojawia, ale funkcja jest wywoływana z tym argumentem: sound(10) • Zjawisko musi wystąpić w definicji funkcji a nie w deklaracji, bo w deklaracji nazwy argumentów i tak są nieistotne. • Wykorzystanie: • Modyfikacja istniejących programów • Niezależne przeciążanie znaczeń post i prefiksowych operatorów inkrementacji i dekrementacji.