Programowanie obiektowe III rok EiT
description
Transcript of Programowanie obiektowe III rok EiT
Programowanie obiektoweIII rok EiT
dr inż. Jerzy KotowskiWykł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
• 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
class String // Część 1/2{
char *s; // nowy elementint 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;} // destruktorvoid 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);
};
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
• 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…
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();
}
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);
• inline i const są używane w celu unikania define.• preprocesor nie zna !! składni języka C.• słowo kluczowe inline jest ż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 const nie może zmieniać swojej wartości.
• Zmienna ze specyfikatorem const może być używana jako literał, to znaczy na przykład jako rozmiar tablicy.
• Obiekt const nie 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 const może być inicjalizowana.
Przykład ..\..\Visual Studio Projects\test0\test0.sln
// circle.cppconst float ppi=3.14159;const int True=1;inline float circum(float rad) {return (ppi*2*rad);}inline float 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 typu const
• 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.
int i=1;void main(void){
int i=2; //redeklaracja{
cout<<"Enter inner block\n";int n=i;int i=3; // kolejna redeklaracjacout<<i<<" i <> :: i "<<::i<<"\n";cout<<"n = "<<n<<"\n";
}cout<<"Enter outer block\n";cout<<i<<" i <> :: i "<<::i<<"\n";getch();
}
• 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
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 n
double 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.cppint greater(int& a,int& b){
if(a>b){
int temp=a;a=b;b=temp;return(1);
}else return(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);else return(mult(n,k-1,a)*n);
}
• Funkcja mult zwraca a*nk
• Przykłady użycia:mult(5); // 52 mult(5,4); // 54 mult(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.