Programowanie obiektowe III rok EiT
description
Transcript of Programowanie obiektowe III rok EiT
Programowanie obiektoweIII rok EiT
dr inż. Jerzy KotowskiWykł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
• C++ for C programmers, Ira Pohl, The Benjamin/Cummings Publishing Company, Inc.
• Symfonia C++, Jerzy Grębosz, Oficyna Kallimach, Kraków 1999
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.
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.
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();
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
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();
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.
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); }
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();
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.
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; … };
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.
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;}
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?
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;
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