Programowanie obiektowe III rok EiT

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

description

Programowanie obiektowe III rok EiT. dr inż. Jerzy Kotowski Wykład XI. Program wykładu. Język C++ Klasy, c.d. konwersja typów przeciążanie i selekcja funkcji funkcje zaprzyjaźnione przeciążanie operatorów – operator konwersji 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 XI

Page 2: Programowanie obiektowe III rok EiT

Program wykładu

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

•konwersja typów •przeciążanie i selekcja funkcji • funkcje zaprzyjaźnione•przeciążanie operatorów – operator

konwersji

• 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

Konwersja typów - tradycyjna

• Wyrażenie arytmetyczne typu x+y charakteryzuje się wartością i typem wartości.

• W trakcie obliczania wartości wyrażeń ma miejsce automatyczna konwersja typów.

• Prawdziwe są następujące reguły konwersji typów:– Wpierw:

• Typy char oraz short są promowane do typu int. • unsigned char i unsigned short są promowane do typu unsigned.

– Następnie:• Jeżeli wyrażenie jest dalej typu mixed expression, wtedy zgodnie z

hierarchią typów: int < unsigned < long < unsigned long < float < double operand niższego typu jest promowany do typu drugiego operandu i wartość całego wyrażenia jest też tego typu.

• Automatyczna konwersja typu ma również miejsce w przypadku operatora podstawiania.

• Istnieje możliwość dokonywania jawnej konwersji przy pomocy operatora rzutowania. Priorytet 15, jednoargumentowy, prawostronnie łączny.

Page 5: Programowanie obiektowe III rok EiT

Konwersja abstrakcyjnych typów danych • Explicit conversion jest niezbędna jeżeli konwersja niejawna

jest niepożądana oraz kiedy brak konwersji jest błędem składni.

• C++ w celu integracji ADT oraz typów built-in dysponuje możliwościami jawnej konwersji z użyciem składni: type_name (expression)

• Przykład:było x=(float)y; jest x=float(y);

było p=(char *)q; jest p=char *(q);typedef char *ptr_c;p=ptr_c(q);

• Konstruktor z jednym argumentem jest operatorem konwersji typu z typu jaki ma argument do typu jaki określa klasa konstruktora.

• String dynamiczny II.cpp• W przykładzie inny jest tylko kod klienta.

Page 6: Programowanie obiektowe III rok EiT

Kod klienta .. \test0.sln

• Z wydruku widać, że wszystkie cztery obiekty zostały utworzone przy pomocy operatora konwersji tzn. konstruktora z jednym argumentem: String::String(char *p)

char *str1="Typem, z ktorego dokonuje sie przeksztalcenia "; char *str2="nie musi byc typ wbudowany."; String a(str1),b(str2); String c="Symfonia C++"; String d=String("Jerzy Grebosz"); cout << endl << " ** Wyniki ** " << endl << endl; a.print(); b.print(); c.print(); d.print(); getch();

Page 7: Programowanie obiektowe III rok EiT

Konwersja z typu ADT .. \test0.sln

• Przedstawiony program String dynamiczny II.cpp prezentuje konwersję typu built-in na typ zdefiniowany przez użytkownika czyli w tym przypadku konwersję z typu char* na typ String.

• Nie jest możliwe dodanie konwersji do istniejącego typu built-in z naszego typu ADT.

• Musimy taką konwersję zdefiniować sami wewnątrz naszej klasy.

• Dokonuje się w tym celu przeciążenia operatora rzutowania.• Składnia ogólnie: operator type() { ... }. • Ten operator jest funkcją składową, która nic nie zwraca i ma

pustą listę argumentów. Nie można jej zatem przeciążać.• Przykład: chcemy dokonać konwersji odwrotnej z typu

String na char*.• Dodajemy jedną składową w definicji klasy String.• Postać operatora: operator char*() { return(s); }

tzn. udostępniamy pole robocze obiektu klasy String.• String dynamiczny III.cpp

Page 8: Programowanie obiektowe III rok EiT

Kod klienta

• Zamiast

• jest

• Usunięcie operatora konwersji skutkuje błędem kompilacji

cout << a; cout << b; cout << endl << c; cout << endl << d;

a.print(); b.print(); c.print(); d.print();

Page 9: Programowanie obiektowe III rok EiT

Przeciążanie i selekcja funkcji

• Przy wywołaniu funkcji przeciążonej kompilator musi uruchomić algorytm selekcji w celu wyboru odpowiedniej funkcji.

• Postać algorytmu selekcji zależy od tego jakiego typu konwersje są dopuszczalne.

• Należy upewnić się jakie reguły dopuszcza kompilator, którym się posługujemy.

• Overloaded Function Selection Algorithm – Kompilator próbuje znaleźć funkcję z idealnie pasującymi typami

argumentów. Przyjmuje się przy tym, że:• short, char oraz stała 0 odpowiadają typowi int,• float odpowiada typowi double.

– Jeżeli to nie wystarcza kompilator próbuje dokonać klasycznej niejawnej konwersji typów dla obiektów typu built-in. Taka konwersja nie ma prawa prowadzić do utraty informacji. Dotyczy ona w związku z tym konwersji wskaźników i następujących rozszerzeń (projekcji na wyższe typy): int do long oraz int do double.

– Następnie kompilator próbuje wykorzystać typy zdefiniowane przez użytkownika o ile prowadzą one do jednoznacznych reguł konwersji.

Page 10: Programowanie obiektowe III rok EiT

Przykład – klasa Complex.cpp .. \test0.sln

• W programie jest przeciążona trzykrotnie funkcja greater.• Kompilator nie zgodził się na wywołanie jej z argumentami typu int

oraz double: ‘greater' : 3 overloads have similar conversions Formal parameter lists are too similar to resolve ambiguity.

class Complex{ double Re,Im;public: Complex(float x=0, float y=0): Re(x), Im(y){} void assign(double r,double i) { Re=r; Im=i; } void print() { cout << Re << "+" << Im << "i "; } operator double() { return(sqrt(Re*Re+Im*Im)); } // konwersja};

inline int greater(int i,int j) { return(i>j?i:j); }inline double greater(double x,double y) { return(x>y?x:y); }inline Complex greater(Complex w,Complex z) { return(w>z?w:z); }

Page 11: Programowanie obiektowe III rok EiT

Kod klienta

• Kompilator wymyślił sobie własną algebrę liczb zespolonych.• Complex greater(Complex w,Complex z)

{return(w>z?w:z);}• Porównanie w>z dokonywane jest poprzez wstępną konwersję

w i v do obiektów typu double bo te można porównać.• Zwracaną wartością jest liczba zespolona o większym module. • Nigdy nie zachodzi konwersja przy zwracaniu wartości

ponieważ jeżeli była potrzebna to już została dokonana przy przekazywaniu argumentów.

• Usunięcie operatora konwersji Complex::operator double() skutkuje błędem kompilacji.

Complex u(1,3), v(2,2),z; z=greater(u,v); cout << "Compare "; u.print(); cout << " and "; v.print(); cout << " : greater is "; z.print();

Page 12: Programowanie obiektowe III rok EiT

Funkcje zaprzyjaźnione – friend functions• Słowo kluczowe friend daje dostęp funkcji, która nie jest

member function do ukrytych składowych klasy. • Filozofia języka C++, a w ogólności OOP, prowadzi do

koncepcji separacji obiektów. Friend functions łamią tę filozofię. Musimy mieć zatem istotny powód, aby z takiego mechanizmu korzystać.

• Powody: – Chcemy zdefiniować funkcję, która będzie miała dostęp do

ukrytych składowych więcej niż jednej klasy równocześnie. – Wszystkie argumenty friend function ma przekazywane przez

listę argumentów. Pozwala to na dokonywanie ukrytej konwersji typów i może być czasami bardzo wygodne i efektywne przy tworzeniu client code. Ma to w szczególności miejsce przy przeciążaniu operatorów.

• Friend function musi się pojawić w deklaracji klasy, do której jest zaprzyjaźniona.

• Nazwa funkcji musi być poprzedzona słowem friend. • Nie ma znaczenia, czy będzie to w bloku private czy też w

bloku public.

Page 13: Programowanie obiektowe III rok EiT

Przykłady składni przyjaźni .. \test0.sln

• Przyjaźń z funkcją zewnętrzną:

• Przyjaźń z funkcjąskładową:

• Przyjaźń z wszystkimifunkcjami składowymi:

• Przykład z friend function - mnożenie wektor * macierz. Powód wykorzystania takiego mechanizmu - potrzeba dostępu do dwóch klas równocześnie.

• Vect_matrix.cpp

class star { … friend void Ala(); int Ola(); … };

class galaxy { … friend int star::Ola(); … };

class cosmos { … friend class galaxy; … };

Page 14: Programowanie obiektowe III rok EiT

Opis programu

• Cel: Stworzenie narzędzia, które pomnoży wektor przez macierz.

• Mnożenie będzie zdefiniowane jako funkcja zewnętrzna. Wymaga to zadeklarowania przyjaźni w obu klasach

• Interesujące elementy programu:– Forward reference – deklaracja zapowiadająca.– Konstruktor kopiujący i przeciążony operator podstawiania

w klasie vect.– Oba elementy są niezbędne. Widać to po debuggingu.– Przeciążony operator podstawiania pojawił się po raz

pierwszy. – Funkcja vect mpy(vect& v,matrix& m) korzysta z

przyjaźni.– Klasa matrix została potraktowana po macoszemu. Akurat

w tym przykładzie nie było potrzeby utworzenia pełnego interfejsu klasy.

Page 15: Programowanie obiektowe III rok EiT

Przeciążony operator podstawiania

• Zdefiniowany jako funkcja składowa

• Na liście argumentów jest tylko prawy argument. Lewym argumentem jestem ‘ja sam’.

• Prawy argument jest udostępniany przez referencję i nie można go zmieniać.

• Operator udostępnia wynik (referencję), czyli lewy argument. Technika udostępnienia wymaga użycia wskaźnika this.

• Użycie: a=b=c; Referencja!!!• Można napisać równieć: a.operator=(b); ale po co?

vect& vect::operator =(const vect &v){ size=v.size; if(p) delete p; p=new int[size]; ub=size-1; for(int i=0;i<size;i++) p[i]=v.p[i]; return *this;}

Page 16: Programowanie obiektowe III rok EiT

vect& vect::operator =(const vect &v){ size=v.size; if(p) delete p; p=new int[size]; ub=size-1; for(int i=0;i<size;i++) p[i]=v.p[i]; return *this;}

Konstruktor kopiujący

• Definicja konstruktora kopiującego jest podejrzanie podobna:

• Można to wykorzystać, aby nie powielać kodu:

vect::vect(const vect &v){ size=v.size; p=new int[size]; ub=size-1; for(int i=0;i<size;i++) p[i]=v.p[i];}

vect::vect(const vect &v){ p=0; *this=v;}

Ta linia musi być Dlaczego?

Page 17: Programowanie obiektowe III rok EiT

Słowo kluczowe operator

• Słowo kluczowe operator służy do:– tworzenia funkcji członkowskiej, która dokonuje konwersji typu– przeciążania operatorów.

• W programie Vect_matrix.cpp nagłówek funkcji vect mpy(vect& v,matrix& m)

może zostać zastąpiony przez vect operator* (vect& v, matrix&

m)• Wywołanie lepiej wygląda. Zamiast instrukcji

y=mpy(x,A); pisze się:

y=x*A;• Lista WSZYSTKICH niezbędnych zmian w programie:

– W definicjach klas prototyp funkcji mpy powinna zastąpić linia: friend vect operator* (vect& v,matrix& m);

– nagłówek funkcji mpy powinien zostać zastąpiony przez vect operator* (vect& v, matrix& m)

– W segmencie main zamiast y=mpy(x,A); ma się pojawić: y=x*A;

Page 18: Programowanie obiektowe III rok EiT

Operator konwersji

• Do przekształcenia jednego typu na drugi mamy dwa narzędzia:– Konstruktor jednoargumentowy:

T::T(K& k);– Funkcję konwertującą (operator konwersji):

K::operator T();• Zdaniem J. Grębosza konwersja jest rozwiązaniem zawsze

lepszym. Wynika to między innymi z następujących faktów:– Nie można zdefiniować konstruktora dla typu wbudowanego.– Nie można napisać konstruktora dla klasy, która nie jest naszą

własnością.– Konstruktor wymaga idealnego dopasowania argumentów.– Konstruktor nie jest dziedziczony przez klasy pochodne a operator

konwersji jest – tak samo jak wszystkie inne funkcje składowe

K Tkonwersja konstruktor