Rzutowanie i konwersje

Podobne dokumenty
Operacje wejścia/wyjścia (odsłona druga) - pliki

Wprowadzenie do szablonów szablony funkcji

Wprowadzenie do szablonów szablony funkcji

Wyliczanie wyrażenia obiekty tymczasowe

Referencje do zmiennych i obiektów

Wartości domyślne, przeciażenia funkcji

Wartości domyślne, przeciażenia funkcji

Pola i metody statyczne

Szablon klasy std::vector

Operacje wejścia/wyjścia odsłona pierwsza

Przesłanianie nazw, przestrzenie nazw

Szablony funkcji i szablony klas

Konstruktor kopiujacy

Wyjątki. Wyjątki. Bogdan Kreczmer. Katedra Cybernetyki i Robotyki Politechnika Wrocławska

Klasa, metody, rozwijanie w linii

Szablon klasy std::list

Lista dwukierunkowa - przykład implementacji destruktorów

Klasa, metody, rozwijanie w linii

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Wyjątki (exceptions)

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Obiekty i metody stałe

Hermetyzacja oraz pola i metody statyczne

Wykład I. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Wstęp do Programowania 2

Style programowania - krótki przeglad

PARADYGMATY PROGRAMOWANIA Wykład 4

Wprowadzenie do szablonów klas

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Pliki wykład 2. Dorota Pylak

PROE wykład 3 klasa string, przeciążanie funkcji, operatory. dr inż. Jacek Naruniec

TEMAT : KLASY DZIEDZICZENIE

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

Dziedziczenie i poliformizm

Programowanie w C++ Wykład 14. Katarzyna Grzelak. 3 czerwca K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 15 kwietnia K.Grzelak (Wykład 8) Programowanie w C++ 1 / 33

Obsługa wyjątków. Język C++ WW12

Język C++ wykład VIII

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Programowanie w C++ Wykład 9. Katarzyna Grzelak. 14 maja K.Grzelak (Wykład 9) Programowanie w C++ 1 / 30

Programowanie obiektowe w C++ Wykład 12

Język C++ wykład VII. uzupełnienie notatek: dr Jerzy Białkowski. Programowanie C/C++ Język C++ wykład VII. dr Jarosław Mederski. Spis.

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Wstęp do programowania obiektowego, wykład 7

referencje Wykład 2. Programowanie (język C++) Referencje (1) int Num = 50; zdefiniowano zmienną Num (typu int) nadając jej wartość początkową 50.

Programowanie 2. Język C++. Wykład 3.

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Programowanie obiektowe - Przykładowe zadania egzaminacyjne (2005/2006)

Wykład V. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Wstęp do programowania

Identyfikacje typu na etapie. wykonania (RTTI)

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Wykład II. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Programowanie obiektowe, wykład nr 7. Przegląd typów strukturalnych - klasy i obiekty - c.d.

Do czego służą klasy?

Programowanie - wykład 4

Dziedziczenie jednobazowe, poliformizm

Wstęp do programowania

Programowanie obiektowe i C++ dla matematyków

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 28 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27

Plik klasy. h deklaracje klas

1 P roste e t ypy p d a d n a ych c - c ąg ą g d a d l a szy 2 T y T py p z ł z o ł żo ż ne e d a d n a ych c : T BLICE

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Zajęcia nr 5 Algorytmy i wskaźniki. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

Programowanie obiektowe w języku C++ dr inż. Jarosław Forenc

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Programowanie obiektowe w języku

Mechanizm dziedziczenia

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 13 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 30

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

C++ wprowadzanie zmiennych

Język C++ Różnice między C a C++

Programowanie Obiektowew języku C++ Zadania L4

Wartości domyślne, szablony funkcji i klas

Podstawy programowania skrót z wykładów:

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Programowanie Obiektowew języku C++ Zadania L4

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Techniki programowania INP001002Wl rok akademicki 2017/18 semestr letni. Wykład 4. Karol Tarnowski A-1 p.

Język ludzki kod maszynowy

TEMAT : KLASY POLIMORFIZM

Wykład 1. Program przedmiotu. Programowanie Obiektowe (język C++) Literatura. Program przedmiotu c.d.:

Do czego służą klasy?

Podstawy języka C++ Maciej Trzebiński. Instytut Fizyki Jądrowej Polskiej Akademii Nauk. Praktyki studenckie na LHC IVedycja,2016r.

Projektowanie klas c.d. Projektowanie klas przykład

Programowanie obiektowe Wykład 3. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21

Pytania sprawdzające wiedzę z programowania C++

Operatory na rzecz typu TString

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 20 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 32

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

Tablice i struktury. czyli złożone typy danych. Programowanie Proceduralne 1

Style programowania - krótki przeglad

Przekazywanie argumentów wskaźniki

Programowanie w języku C++

Programowanie w języku C++

Podstawy Programowania Obiektowego

Geneza powstania języka C++

Transkrypt:

Rzutowanie i konwersje Bogdan Kreczmer ZPCiR IIAiR PWr pokój 307 budynek C3 bogdan.kreczmer@pwr.wroc.pl Copyright c 2005 2013 Bogdan Kreczmer Niniejszy dokument zawiera materiały do wykładu na temat programowania obiektowego. Jest on udostępniony pod warunkiem wykorzystania wyłacznie do własnych prywatnych potrzeb i może on być kopiowany wyłacznie w całości, razem z niniejsza strona tytułowa.

Domyślne konwersje typów struct Wektor2f //.................................................................... float x, y; Wektor2f( float x=0, float y=0 ): x(x), y(y) ; //.................................................................................... struct LZespolona //................................................................. float re, im; LZespolona( ): re( ), im( ) // W ten sposób pola re i im będa miały wartość 0. ; //..................................................................................... void Funkcja dla Wektora( Wektor2f const & W )... LZespolona Z; Wektor2f W = Z; Funkcja dla Wektora( Z );... //Tu jest bład. Brak zgodności typów. //Tu także jest bład z tego samego powodu. Ze względu na wymóg statycznej zgodności typów powyższe operacje sa niepoprawne. Niezgodności typów wykrywane sa w trakcie kompilacji. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 1

Domyślne konwersje typów... struct Wektor2f //......................................................................... float x, y; Wektor2f( LZespolona const& Z ); // Ten konstruktor umożliwia konwersje typów. Wektor2f( float x=0, float y=0 ): x(x), y(y) ; //............................................................................................ Wektor2f::Wektor2f( LZespolona const& Z ): x(z. re ), y(z. im ) void Funkcja dla Wektora( const Wektor2f & W )... LZespolona Z; Wektor2f W = Z; // Tu jest dobrze gdyż możliwa jest niejawna konwersja. Funkcja dla Wektora( Z );... // Tu jest dobrze. Dodatkowy konstruktor daje przepis jak z obiektu klasy Wektor2f stworzyć obiekt klasy LZespolona. Dlatego kompilator może sam rozwiazać napotkany problem niezgodności typów. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 2

Bezpieczne rzutowanie struct Wektor2f //............................................................................. float x, y; Wektor2f( const LZespolona & Z ); // Ten konstruktor umożliwia konwersje typów. Wektor2f( float x=0, float y=0 ): x(x), y(y) ; //................................................................................................ Wektor2f::Wektor2f( const LZespolona & Z ): x(z. re ), y(z. im ) LZespolona Z; Wektor2f W1 = Z; // Tu jest dobrze gdyż możliwa jest niejawna konwersja. Wektor2f W2 = Wektor2f(Z); // Jawna konwersja poprzez wywołanie konstruktora. Wektor2f W3 = static cast<wektor2f>(z); // Jawna konwersja poprzez bezpieczne rzutowanie. Rzutowanie typu obiektu można dokonać w sposób jawny i bezpieczny za pomoca operatora static cast. Stosowanie tego operatora jest zalecane zamiast realizacji niejawnych rzutowań. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 3

Domyślne konwersje typów struct Wektor2f //................................................................................. float x, y; explicit Wektor2f( LZespolona const& Z ); // Znowu zmiana Wektor2f( float x=0, float y=0 ): x(x), y(y) ; //.................................................................................................... Wektor2f::Wektor2f( LZespolona const& Z ): x(z. re ), y(z. im ) void Funkcja dla Wektora( const Wektor2f & W )... LZespolona Z; Wektor2f W = Z; // Tu jest źle gdyż niejawna konwersja jest teraz zabroniona. Funkcja dla Wektora( Wektor2f( Z ) ); Funkcja dla Wektora( static cast<wektor2f>( Z ) ); // Tu jest dobrze, gdyż konwersja jest wykonana w sposób jawny. // Najlepszy sposób, konwersja poprzez jawne rzutowanie. Niejawna konwersja nie zawsze jest pożadana. Czasami może być źródłem błędów bardzo trudnych do wykrycia. Słowo kluczowe explicit pozwala zabronić niejawnych wywołań wybranych konstruktorów, tym samym konwersji z zastosowaniem tego konstruktora. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 4

Konwertery struct Wektor2f //................................................................................. float x, y; Wektor2f( float x=0, float y=0 ): x(x), y(y) ; //................................................................................................. struct LZespolona //............................................................................. float re, im; operator Wektor2f ( ) return Wektor2f( re, im); // Deklaracja i implementacja konwertera ; //................................................................................................. void Funkcja dla Wektora( const Wektor2f & W )... LZespolona Z; Wektor2f W = Z; // Konwersje moga wykonywać się niejawnie Funkcja dla Wektora( (Wektor2f ) Z ); // lub też można je wykonywać w sposób jawny (w stylu C) Funkcja dla Wektora( static cast<wektor2f>( Z ) ); // Najlepszy sposób, konwersja poprzez jawne rzutowanie. Operatory konwersji dostarczaja bardziej ogólnego mechanizmu przekształcania typu niż konstruktory. Dla konwerterów nie można zabronić konwersji domyślnych. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 5

Konwertery struct Wektor2f //......................................................................... float x, y; Wektor2f( float x=0, float y=0 ): x(x), y(y) ; //......................................................................................... struct LZespolona //..................................................................... float re, im; operator Wektor2f ( ) return Wektor2f( re, im); // Deklaracja i implementacja konwertera ; //......................................................................................... void Fun Zmieniajaca Wek( Wektor2f &W )... LZespolona Z; Fun Zmieniajaca Wek( Z ); // Tu nie może być już zastosowany konwerter do klasy Wektor2f, gdyż w tym... // przypadku potrzebna jest konwersja do typu Wektor2f&. Wymaganie ścisłej zgodności typów zapobiega błędnym domyślnym użyciom konwerterów. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 6

Konwertery struct Wektor2f //......................................................................... float x, y; Wektor2f( float x=0, float y=0 ): x(x), y(y) ; //......................................................................................... struct LZespolona //..................................................................... float re, im; operator Wektor2f & ( ) Wektor2f W( re, im); return W; // Błędna implementacja ; //......................................................................................... void Fun Zmieniajaca Wek( Wektor2f &W )... LZespolona Z; Fun Zmieniajaca Wek( Z );... // Tu byłoby już wszystko dobrze gdyby konwerter był poprawnie zaimplementowany. Wszystkie uwagi odnoszace się do zwracanych wartości (obiektów, referencji itd.) przez metody odnosza się również do konwerterów. Konwerter do referencji danej klasy nie może zwracać referencji do obiektu lokalnego. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 7

Konwertery struct Wektor2f float x, y; ; //.............................................................. struct LZespolona //............................................................................. Wektor2f Wek; float & re, & im; LZespolona( ): re( Wek. x ), im( Wek. y ) operator Wektor2f & ( ) return Wek; // Deklaracja konwertera ; //................................................................................................. void Fun Zmieniajaca Wek( Wektor2f &W )... LZespolona Z; Wektor2f W = Z; // Podstawienie jest poprawne dzięki niejawnej konwersji. Z = W; static cast<wektor2f &>(Z) = W; Fun Zmieniajaca Wek( Z );... // To podstawienie jest błędne. Nie jest możliwa domyślna konwersja po prawej stronie operatora. // Tutaj jest już wszystko dobrze. // Dzięki konwerterowi przekazanie parametru jest poprawne. Konwersja do referencji musi odnosić się do obiektu znajdujacego się w obrębie zakresu definicji danego konwertera (dotyczy to ogólnie wszystkich metod i funkcji). Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 8

Konwertery struct LZespolona //..................................................................... float x, y; operator float ( ) const return x x + y y; ; //......................................................................................... int main() LZespolona Z; float d = Z; // To jest poprawne dzięki domyślnej konwersji do float. if ( Z ) cout << Różne od zera << endl; // To także jest poprawne. d = d + Z - 5; // Konwersja w tym miejscu być może nie jest pożadana w przypadku,... // gdy zmienna Z użyto przez pomyłkę. Nad- Operatory konwersji zapewniaja konwersję danej klasy do dowolnego typu wbudowanego. mierne korzystanie z tego mechanizmu może jednak być niebezpieczne. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 9

Konwertery struct LZespolona //............................................................................. float x, y; operator float ( ) const return x x + y y; operator bool( ) const return x y; ; //................................................................................................. int main() LZespolona Z; float d = Z; // To jest poprawne dzięki domyślnej konwersji do float. if ( Z ) cout << Różne od zera << endl; // Teraz jest tu użyta konwersja do typu bool. d = d + Z - 5; d = d + static cast<float>(z) - 5;... // W tym przypadku konwersja staje się niejednoznaczna dlatego wyrażenie to nie jest akceptowalne. // Należy dokonać jawnej konwersji aby wszystko było dobrze. Zdefiniowanie konwersji do kilku typów podstawowych może prowadzić do niejednoznaczności. Może to być pożyteczne, gdyż zabezpiecza przed przypadkowym użyciem danej zmiennej w innym kontekście. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 10

Konwertery Zapis operacji odczytu z cin można znacznie uprościć. Jest to możliwe dzięki temu, że dla klasy std::istream przeciażenie operatora >> zwraca referencję do std::istream (obiekt zwraca referencję do samego siebie) oraz zdefiniowany jest operator konwersji do typu void*, który zwraca zanegowany wynik metody fail. float d; do cin >> d; if ( cin.fail( ) ) break ;... while (true); = float d; while (!(cin >> d).fail( ) )... float d; while (cin >> d) // Wykonuj dopóki poprawnie... // odczytasz wartość typu float Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 11

Czytanie z pliku #include <iostream> #include <fstream> using namespace std; #include <iostream> #include <fstream> using namespace std; ifstream char Strm; Znak; ifstream Strm( plik.txt ); char Znak; Strm.open( plik.txt ); if (!Strm.is open( ) ) return 1; Strm >> noskipws >> Znak; while ( Strm.good( ) ) cout << Znak; Strm >> Znak; Strm.close( ); if (!Strm ) return 1; Strm >> noskipws; while ( Strm >>Znak ) cout << Znak; Zdefiniowany konwerter do typu void oraz przeciażenie operatora! pozwalaja uprościć zapis operacji sprawdzania stanu strumienia. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 12

Operatory rzutowania const cast rzutowanie usuwajace modyfikatory const oraz volatile. Całość konwersji realizowana jest przez kompilator. Rzutowanie to należy do rzutowań bezpiecznych. static cast używany do zdefiniowanych przez użytkownika, standardowych lub niejawnych konwersji typów. Całość konwersji realizowana jest przez kompilator. Rzutowanie to należy do rzutowań w zasadzie bezpiecznych. reinterpret cast jest najbardziej niebezpiecznym rzutowaniem. Wykonuje on konwersję między wskaźnikami oraz wskaźnikami i liczbami. Źle przeprowadzone rzutowanie może być źródłem błędów trudnych do wykrycia. dynamic cast obsługuje tylko obiekty klas polimorficznych. Zapewnia realizację rzutowania w górę. Rzutowanie to należy do rzutowań bezpiecznych. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 13

Operator const cast< > class LZespolona //........................................................ public : float re, im; void Zmien( float re, float im ) re = re; im = im; float Re( ) const return re; float Im( ) const return im; ; //........................................................................... const LZespolona LZespolona StaleZ; ZmienZ; const cast<lzespolona&>(stalez).zmien(2,3); const cast<lzespolona>(stalez).zmien(2,3); const cast<const LZespolona&>(ZmienZ).Re( ); Rzutowanie z wykorzystaniem operatora const cast może być tylko rzutowaniem na wskaźnik lub referencję. Może ono usuwać lub dodawać modyfikator const. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 14

const int Stala = 5; volatile int ZmUlotna; const cast<int &>(Stala) = 5; const cast<int &>(ZmUlotna) = 5; Operator const cast< > const cast<const int &>(ZmUlotna) = 5; const cast<volatile int &>(Stala) = 5; const cast< int >(ZmUlotna) = 5; const char Tab[ ] = łódka ; const cast<char >( Tab )[ 0 ] = w ; const cast<char >( Tab ) = w ; Przy rzutowaniu za pomoca const cast sa te same zasady do modyfikator const jak też modyfikatora volatile. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 15

unsigned int ZmBezZnaku = 5; int ZmZeZnakiem = 50; Operator static cast< > ZmBezZnaku = static cast<unsigned int >(ZmZeZnakiem); static cast<int &>(ZmBezZnaku) = ZmZeZnakiem; static cast<int >(ZmBezZnaku) = ZmZeZnakiem; double ZmDouble = numeric limits<double >::max( ); float ZmFloat = static cast<float >(ZmDouble); cout << ZmDouble: << ZmDouble << endl; cout << ZmFloat: << ZmFloat << endl; cout << ZmBezZnaku: << ZmBezZnaku << endl; Wynik działania: ZmDouble: 1.79769e+308 ZmFloat: inf ZmBezZnaku: 4294967246 W przypadku typów wbudowanych nie można rzutować na referencję. Jest to możliwe w przypadku klas, dla których zdefiniowane zostały odpowiednie konwertery. Jeżeli rzutowanie realizowane jest na wartość, to produkt rzutowania nie jest l-wartościa. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 16

int ZmInt = 32111; double ZmDouble = ZmInt; Operator static cast< > ZmDouble = ZmInt; ZmDouble = static cast <double >(ZmInt); ZmDouble = 6.25; ZmInt = ZmDouble; ZmInt = static cast <int >(ZmDouble); // Domyślne rzutowanie // Rzutowanie jawne // Tu kompilator będzie ostrzegał // Tu już nie cout << ZmInt: << ZmInt << endl; Wynik kompilacji: jk@noxon PRG> g++ konwersja.cpp konwersja.cpp: In function int main() : konwersja.cpp:7: warning: converting to int from double Wynik działania: ZmInt: 6 W przypadku rzutowań stratnych należy rzutowania dokonywać w sposób jawny. W ten sposób eliminujemy zbędne komunikaty i poprawiamy czytelność programu. Nie wszystkie kompilatory domyślnie ostrzegaja przed stratnymi rzutowaniami. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 17

Operator static cast< > short int ZmSInt Pomocnicza = 5; short int ZmSInt = 32111; double ZmDouble = ZmSInt; void wzm = &ZmSInt; static cast <double >(wzm) = ZmDouble; short int wzmsint = &ZmSInt; static cast <double >(wzmsint) = ZmDouble; // To kompilator wykryje cout << ZmSInt Pomocnicza: << ZmSInt Pomocnicza << endl; cout << ZmSInt << ZmSInt << endl; cout << ZmDouble: << ZmDouble << endl; Wynik działania: ZmSInt Pomocnicza: 0 ZmSInt: 0 ZmDouble: 32111 Wykorzystywanie wskaźników na typ void może prowadzić do bardzo niebezpiecznych konstrukcji. Z tego względu należy unikać tego typu rozwiazań. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 18

Operator reinterpret cast< > class KlasaInt2 //............................................................................... public : int Pole1, Pole2; ; //............................................................................................... KlasaInt2 Ob; int Zm = 30; Ob. Pole1 = 100; Ob. Pole2 = 200; int Tab = reinterpret cast <int >(&Ob); cout << Tab[0]: << Tab[0] << endl; cout << Tab[1]: << Tab[1] << endl; KlasaInt2 &ZlyOb = reinterpret cast <KlasaInt2 &>(Zm); cout << ZlyOb. Pole1: << ZlyOb. Pole1 << endl; cout << ZlyOb. Pole2: << ZlyOb. Pole2 << endl; Wynik działania: Tab[0]: 100 Tab[1]: 200 ZlyOb. Pole1: 30 ZlyOb. Pole2: 100 Stosowanie operatora reinterpret cast daje możliwości swobodnego manipulowania organizacja pamięci. Jednak stwarza to potencjalnie duże niebezpieczeństwo wystapienia bardzo poważnych błędów. Powoduje również, że program zazwyczaj staje się nieprzenośny. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 19

Rzutowanie w górę Rzutowanie w górę jest rzutowaniem na klasę bazowa. Tego typu rzutowanie zawsze się powiedzie, gdyż obiekt klasy pochodnej musi zawierać podobiekt klasy bazowej. Z tego powodu rzutowanie to może być realizowane niejawnie. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 20

Operator dynamic cast< > class KlasaBazowa //........................................................................... public : virtual KlasaBazowa( ) ; //............................................................................................... class KlasaPochodna: public KlasaBazowa ; //.............................................. KlasaBazowa KlasaPochodna wobbazo; ObPoch; KlasaBazowa &ObBazo = ObPoch; // Niejawne rzutowanie referencji wobbazo = &ObPoch; wobbazo = dynamic cast<klasabazowa >(&ObPoch); // Jawne rzutowanie w górę Rzutowanie w górę jest rzutowaniem całkowicie bezpiecznym. Rzutowanie to może odnosić się zarówno do wskaźników jak też do referencji. Może być również wykonywane niejawne na parametrach wywołania funkcji lub metod. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 21

Niejawne rzutowanie w górę class KlasaBazowa //........................................................................... public : virtual KlasaBazowa( ) ; //............................................................................................... class KlasaPochodna: public KlasaBazowa ; //.............................................. void Funkcja( KlasaBazowa & Ob )... KlasaPochodna Funkcja( ObPoch ); ObPoch; // Tu następuje niejawne rzutowanie w górę. W przypadku parametrów wywołania funkcji lub metod niejawne rzutowanie w górę realizowane jest niezależnie od tego czy parametry te sa modyfikowalne, czy też nie. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 22

Rzutowanie w dół Rzutowanie w dół jest rzutowaniem na klasę pochodna. Ze względu na to, że obiekt klasy bazowej nie zawsze musi być składnikiem obiektu klasy pochodnej (np. może występować samodzielnie), rzutowanie to może się nie powieść. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 23

Operator dynamic cast< > class KlasaBazowa //........................................................................... public : virtual KlasaBazowa( ) ; //............................................................................................... class KlasaPochodna: public KlasaBazowa ; //.............................................. KlasaBazowa KlasaPochodna ObBazo, wobbazoa = &ObBazo, wobbazob; ObPoch, wobpoch; wobbazob = &ObPoch; KlasaPochodna &robpoch = dynamic cast <KlasaPochodna&>( wobbazob); wobpoch = dynamic cast <KlasaPochodna >(wobbazob); cout << Adres: << wobpoch << endl; wobpoch = dynamic cast <KlasaPochodna >(wobbazoa); cout << Adres: << wobpoch << endl; Wynik działania: Adres: 0xbf9c0880 Adres: 0 Wykonujac rzutowanie w dół jeśli obiekt klasy bazowej nie jest częścia składowa obiektu klasy pochodnej, w przypadku rzutowania wskaźnika otrzymywany jest adres NULL, zaś w przypadku rzutowania referencji zgłaszany jest wyjatek bad cast. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 24

Operator dynamic cast< > class KlasaBazowa //........................................................................... public : virtual KlasaBazowa( ) ; //............................................................................................... class KlasaPochodna: public KlasaBazowa ; //.............................................. KlasaBazowa ObBazo, wobbazoa = &ObBazo, wobbazob; KlasaPochodna ObPoch, wobpoch; wobbazob = &ObPoch; wobpoch = dynamic cast <KlasaPochodna >(wobbazob); cout << Adres: << wobpoch << endl; wobpoch = static cast <KlasaPochodna >(wobbazob); cout << Adres: << wobpoch << endl; wobpoch = static cast <KlasaPochodna >(wobbazoa); cout << Adres: << wobpoch << endl; Wynik działania: Adres: 0xbfa48210 Adres: 0xbfa48210 Adres: 0xbfa48230 Wykorzystanie operatora dynamic cast wiaże się z dodatkowym narzutem. Zastosowanie w takich przypadkach operatora static cast daje bardziej efektywny kod, jednak jest bardziej niebezpieczne. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 25

Podsumowanie Operatory konwersji wraz z innymi operatorami dostarczaja bardzo silnego mechanizmu, który pozwala traktować klasy definiowane przez programistę na równi z typami wbudowanymi. Nadużywanie mechanizmu domyślnych konwersji jest potencjalnie bardzo niebezpieczne, gdyż może prowadzić do błędów, które sa bardzo trudno wykrywalne. Moga one prowadzić do utraty kontroli nad przebiegiem obliczeń. Z tych powodów należy: definiować operatory konwersji tylko dla sytuacji jasno określonych nie prowadzacych do dwuznacznych interpretacji, tzn. sytuacji, w których czasami konwersja domyślna może być pożadana, zaś w innych nie. wprowadzona domyślna konwersja nie powinna powodować znaczacego zwiększenia przypadkowych podstawień. w przypadku definiowania konstruktorów jednoargumentowych, które nie sa przewidziane do konwersji typów, należy je definiować jako explicit. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 26

1. Dany jest fragment kodu: Pytania i ćwiczenia struct Wektor2f float x, y; Wektor2f(float w): x(w), y(w) operator float () const return x x + y y; Wektor2f operator + (Wektor2f W) const W. x += x; W. y += y; return W; ; Wektor2f Wek(2); float Liczba = 1; Liczba = 2 + Wek Liczba;... (a) Jaka będzie wartość zmiennej Liczba po wykonaniu powyższego wyrażenia arytmetycznego? (b) Które z metod klasy Wektor2f i ile razy zostana uruchomione w trakcie wyliczania tego wyrażenia? (c) Czy wystapi niejawne wywołanie konstruktora klasy Wektor2f? 2. Dla przykładu jak powyżej rozważmy zamiast wcześniej przedstawionego wyrażenia, wyrażenie: Liczba += Wek = 2 + Wek Liczba; Należy odpowiedzieć na pytania przedstawione w poprzednim punkcie. Copyright c 2005 2013 Bogdan Kreczmer Rzutowanie i konwersje 27