Programowanie obiektowe III rok EiT

18
Programowanie obiektowe III rok EiT dr inż. Jerzy Kotowski Wykład XII

description

Programowanie obiektowe III rok EiT. dr inż. Jerzy Kotowski Wykład XII. Program wykładu. Język C++ Klasy, c.d. przeciążanie (przeładowanie) operatorów Przykład problemu Podstawy języka JAVA Klasówka. Literatura. - PowerPoint PPT Presentation

Transcript of Programowanie obiektowe III rok EiT

Page 1: Programowanie obiektowe III rok EiT

Programowanie obiektoweIII rok EiT

dr inż. Jerzy KotowskiWykład XII

Page 2: Programowanie obiektowe III rok EiT

Program wykładu

• Język C++– Klasy, c.d.

•przeciążanie (przeładowanie) operatorów

• Przykład problemu• Podstawy języka JAVA

•Klasówka

Page 3: Programowanie obiektowe III rok EiT

Literatura

• C++ for C programmers, Ira Pohl, The Benjamin/Cummings Publishing Company, Inc.

• Symfonia C++, Jerzy Grębosz, Oficyna Kallimach, Kraków 1999

Page 4: Programowanie obiektowe III rok EiT

Reguły przeciążania operatorów• Przeciążenia operatora dokonuje się definiując swoją własną

funkcję, która:– Nazywa się operator@ gdzie @ jest operatorem, o którego

przeładowanie nam chodzi.– Co najmniej jeden z argumentów jest obiektem danej klasy.

• Składnia: typ operator@(argumenty)• Lista operatorów, które mogą być przeładowane:

+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* -> new delete () []

• Operatory & * - +

mogą być przeciążane w zarówno w wersji jednoargumentowej jak i dwuargumentowej.

• Lista operatorów, które nie mogą być przeciążane:. .* :: ?:

Page 5: Programowanie obiektowe III rok EiT

Reguły przeciążania operatorów c.d.• Przeciążać można wymienione operatory i tylko te. • Za wyjątkiem operatorów new i delete nie ma ograniczeń na

typ zwracanej wartości.• Nie można zmieniać priorytetu operatora.• Nie można zmieniać liczby argumentów operatora.• Nie można zmieniać łączności operatora.• Ten sam operator można przeciążyć wielokrotnie.• Przynajmniej jeden z argumentów musi być typu

zdefiniowanego przez użytkownika. Nie ma znaczenia który.• Jeżeli funkcja operatorowa jest zdefiniowana jako funkcja

zewnętrzna (tzn. nie jako funkcja składowa w klasie) to liczba argumentów na liście musi się zgadzać z liczbą, na której pracuje operator.

• W przypadku operatora definiowanego jako funkcja składowa lista argumentów nie zawiera lewego operandu. Jest nim obiekt typu klasa, w której dokonuje się takiego przeciążenia.

• Operatory predefiniowane: = & , new delete

Page 6: Programowanie obiektowe III rok EiT

Przeciążamy co popadnie .. \test0.sln

• Program vect1.cpp

class vect { int *p; int size;public: int ub; // upper bound = size-1 vect(int n=10); // konstruktor z domniemanym argumentem vect(const vect &v); // konstruktor kopiujący ~vect() { delete p; } // destruktor vect& operator =(const vect &v); // operator podstawiania int operator ==(const vect &v) const;// porównanie wektorów int& operator[](int i); // operator indeksowy vect operator+(const vect &v) const;// dodawanie wektorów vect operator-(const vect &v) const;// odejmowanie wektorów int operator*(const vect &v) const; // iloczyn skalarny vect operator*(int a) const;// mnożenie wektora przez skalar void operator !() const; // print};

Page 7: Programowanie obiektowe III rok EiT

Opis interfejsu klasy

• Operator podstawiania i operator indeksowy udostępniają odpowiednie obiekty. Przeciążenie operatora podstawiania jest niezbędne do poprawnej pracy programu.

• Wszystkie pozostałe przeciążone operatory obiecują nie zmieniać swoich operandów. Podobnie deklaruje konstruktor kopiujący.

• Wielokrotnie korzystano ze słowa kluczowego this np. w składni vect temp(*this);

• Mnożenie wektora przez liczbę zdefiniowano jako funkcję składową w klasie. Było to możliwe bo lewy argument jest w tym przypadku obiektem klasy.

• Mnożenie liczby przez wektor zdefiniowano jako funkcję zewnętrzną ze względu na to, że lewy argument jest obiektem typu build-in.

• Definicja ta korzysta z funkcji składowej i jest bardzo prosta ale formalnie jest niezbędna: vect operator*(int a, const vect &v)

{return v*a;

}

Page 8: Programowanie obiektowe III rok EiT

Kod klienta - opis

• Zakładamy trzy wektory trójelementowe a, b, c.• Do dwóch pierwszych coś podstawiamy za pomocą

przeciążonego operatora indeksowego.• Do wektora c podstawiamy wartość wyrażenia 2*a-b.• Wyprowadzamy wartości wektorów a, b, c przy pomocy

przeciążonego operatora logicznej negacji.• Na koniec wyprowadzamy wartość iloczynu skalarnego a*b.

• Prawidłowy jest napis vect d[5];

Jest to 5-elementowa tablica obiektów typu vect zakładanych przy pomocy konstruktora domniemanego, to znaczy 10-elementowych.

• Użycie: d[2][3] = 7;

• W powyższej instrukcji użyto dwóch różnych operatorów indeksowych: wbudowanego i przeciążonego.

Page 9: Programowanie obiektowe III rok EiT

Klasa histogram .. \test0.sln

• Cel: przeciążenie operatora << dopisującego nową wartość do histogramu.

• Interfejs klasy zawiera tylko niezbędne elementy.

• Na potrzeby kodu klienta potrzebne są poniższe własności klasy:– Dynamiczna rezerwacja pamięci– Klasa ma mieć zabezpieczenie przed wyjściem

poza obszar histogramu.– Łączność operatora << w celu umożliwienia

napisów typu: h << a << b;• histogram.cpp

Page 10: Programowanie obiektowe III rok EiT

Definicja klasy histogram

class histogram{ double min; // dolna granica double max; // górna granica int przedz; // liczba przedziałów double * adlk; // wskaźnik do tablicy liczników double szer; // szerokość przedziałupublic: histogram(double=0.0,double=1.0,int=10); // konstruktor ~histogram (){ delete [] adlk; } // destruktor histogram & operator << (double); // dorzuca wartość int operator [] (int); // licznik - zwraca wartość pola};

Page 11: Programowanie obiektowe III rok EiT

Najważniejsze elementy klasy

• Przeciążony operator udostępnia „siebie” co rozwiązuje problem łączności operatora:– histogram&– return (*this);

histogram& histogram::operator<<(double w){ int np=(w-min)/szer; if((np >= 0)&&(np<=przedz-1)) adlk[np]++; //tylko "dobre" wartości return (*this);}int histogram::operator [] (int n){ if((n<0) || (n>=przedz)) n=0; return adlk[n];}

Page 12: Programowanie obiektowe III rok EiT

Kod klienta

void main(void){ const int lprzedz=4; double min=0, max=5, szer=(max-min)/lprzedz; histogram h(min,max,lprzedz);// cztery przedziały od 0 do 5 h << 1.5 << 2.4 << 3.8 << 3.0 << 2.0 << 3.5 << 2.8 << 4.6; h << 12.0 << -3.5; for (int i=0;i<10;i++) h << i/2.0; cout << "Przedzial liczba\n"; for(i=0;i<lprzedz;i++) cout << "[" << i*szer << ", " << (i+1)*szer << "]\t" << h[i] << "\n"; getch();}

Page 13: Programowanie obiektowe III rok EiT

Przeciążanie operatorów inkrementacji i dekrementacji• Nienazwany argument pozwala przeciążać operatory

inkrementacji i dekrementacji jako składowe klasy tak, aby można było odróżnić znaczenia post i prefiksowe.

• Przypomnienie: void Ala(int)• Nienazwany argument występuje w definicji i w prototypie. • Operator z jednym argumentem udaje operator

dwuargumentowy i ten drugi argument może być argumentem nienazwanym.

• Odpowiada to składni x operator y, gdzie pierwszy argument to “ja sam” a drugiego może nie być.

• Czyli: x++ to przeciążenie operatora z dwoma a ++x przeciążenie operatora z jednym argumentem.

• Przykład: class String{public: String& operator ++(); String operator ++(int);};

Page 14: Programowanie obiektowe III rok EiT

Klasa String .. \test0.sln

class String{ // String dynamiczny IV.cpp char *s; int len; static Stan;public: String(void); String(int n); String(const char *p); String(const String& str); ~String() { delete s; } int lenght() const { return(len); } String& operator =(const String &str);// operator podstawiania void print() const {cout << s << "\nLenght: " << len << "\n";} void operator !() const {print();} // print operator char *() const { return(s); }// operator konwersji static void switch_stan(void); String& operator ++(void); // małe na duże i zwraca nowy String operator ++(int); // małe na duże i zwraca stary String& operator --(void); // duże na małe i zwraca nowy String operator --(int); // duże na małe i zwraca stary friend String operator +(const String str1, const String str2);};

Page 15: Programowanie obiektowe III rok EiT

Interesujące elementy klasy String• Klasa String podobnie jak poprzednio ma cztery konstruktory• Konstruktor kopiujący korzysta z przeciążonego operatora

podstawiania• Pojawił się przeciążony operator dodawania zdefiniowany jako

funkcja globalna zaprzyjaźniona z klasą:friend String operator +(const String str1, const String str2);

• Wszędzie gdzie jest to możliwe pojawiło się słowo kluczowe const

• Dokonano przeciążenia jednoargumentowego operatora logicznego !

• String& operator ++(void); zamienia małe litery na duże i zwraca nowy string jako referencję

• String operator ++(int); zamienia małe litery na duże i zwraca stary string przez kopiowanie

• String& operator --(void); zamienia duże litery na małe i zwraca nowy string jako referencję

• String operator --(int); zamienia duże litery na małe i zwraca stary string przez kopiowanie

Page 16: Programowanie obiektowe III rok EiT

Wybrane definicje funkcji

String::String(const String& str) { s=0; (*this)=str;}

String& String::operator ++(void) { char mm = 'A' - 'a'; for(int i=0; i<len; i++)

if(s[i] >='a' && s[i] <='z') s[i] += mm; return (*this);}

String String::operator ++(int){ String temp(*this); char mm = 'A' - 'a'; for(int i=0; i<len; i++)

if(s[i] >='a' && s[i] <='z') s[i] += mm; return temp;} String operator +(const String str1, const String str2)

{ String temp(str1.len+str2.len); strcpy(temp.s,str1.s); strcat(temp.s,str2.s); return temp;}

Page 17: Programowanie obiektowe III rok EiT

Coś za coś

• Operator dodawania obiektów klasy String:String operator +(const String str1, const String str2)można zdefiniować jako funkcję składową w klasie:String String::operator +(const String& str) const

• Korzyści: Niepotrzebna jest już przyjaźń• Straty: Nie ma możliwości dokonywania niejawnej

konwersji argumentów. Związane jest to z faktem, że napis a+b jest równoważny napisowi a.operator+(b). Nie można zatem w kodzie klienta napisać na przykład c=a+b jeżeli a nie jest typu String.

• Ewentualne pytanka na klasówkę:– W jaki sposób wykonywana jest linia: cout << a+b;– W jaki sposób wykonywana jest linia: cout << str1+b;– Czy kompilator przeżyje coś takiego: cout << str1+str2;

Page 18: Programowanie obiektowe III rok EiT

Analogie – klasa Complex

• Należy usunąć konwersję na typ double bo prowadzi ona do niejednoznaczności w wyrażeniu 1+a: error C2666: 'operator`+'' : 2 overloads have similar conversions

class Complex { double Re,Im;public: Complex(float x=0, float y=0): Re(x), Im(y){} void print() { cout << Re << "+" << Im << "i "; }// operator double() { return(sqrt(Re*Re+Im*Im)); } trzeba usunąć!!! friend Complex operator+(Complex z1, Complex z2);};Complex operator+(Complex z1, Complex z2){ // Operator dodawania przeciążony jako funkcja globalna Complex temp; temp.Re=z1.Re+z2.Re; temp.Im=z1.Im+z2.Im; return temp;}void main(void){ Complex a(1,5),b(0,-2),c; cout << "\na= "; a.print(); cout << "\nb= "; b.print(); c=1+a+b; cout << "\n1+a+b= "; c.print(); // Niejawna konwersja argumentu getch();}