Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++,...

43
Programowanie Obiektowo Zorientowane w języku c++ Rzutowania Miroslaw Glowacki 1,2 1 Akademia Górniczo-Hutnicza im. Stanislawa Staszica w Krakowie Wydzial Inżynierii Metali i Informatyki Stosowanej Katedra Informatyki Stosowanej i Modelowania 2 Uniwersytet im. Jana Kochanowskiego w Kielcach Wydzial Nauk Ścislych i Przyrodniczych Instytut Fizyki Zaklad Fizyki Komputerowej i Informatyki Listopad 2016 / Październik 2020 Miroslaw Glowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 1 / 43

Transcript of Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++,...

Page 1: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Programowanie Obiektowo Zorientowanew języku c++

Rzutowania

Mirosław Głowacki 1,2

1Akademia Górniczo-Hutnicza im. Stanisława Staszica w KrakowieWydział Inżynierii Metali i Informatyki StosowanejKatedra Informatyki Stosowanej i Modelowania

2Uniwersytet im. Jana Kochanowskiego w KielcachWydział Nauk Ścisłych i Przyrodniczych

Instytut FizykiZakład Fizyki Komputerowej i Informatyki

Listopad 2016 / Październik 2020

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 1 / 43

Page 2: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Spis treści

1 Geneza rzutowania

2 Rzutowania w języku C++

3 Rzutowanie statyczne

4 Rzutowanie typu const

5 Rzutowanie reinterpretacyjne

6 Rzutowanie dynamiczne

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 2 / 43

Page 3: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Spis treści

1 Geneza rzutowania

2 Rzutowania w języku C++

3 Rzutowanie statyczne

4 Rzutowanie typu const

5 Rzutowanie reinterpretacyjne

6 Rzutowanie dynamiczne

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 3 / 43

Page 4: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rozbieżności C i C++

W C++ w stosunku do C została zaostrzona kontrola typów.

Główna zmiana dotyczy wskaźników na typ void* - w C możnabyło przypisywać wskaźniki void* do każdych innych.

W C++ wskaźniki void* są na równi z innymi typami.

Kod napisany w C powinien być bez problemu kompilowany wC++, lecz istnieje kilka rozbieżności od tej zasady - jedna z nichdotyczy właśnie typu void*.

Kod bez problemu przyjmowany przez kompilatory języka C:

int *wskaznik = malloc(sizeof(int));

nie zostanie skompilowany w kompilatorze C++ z powoduzaostrzonej kontroli typów, gdyż malloc zwraca void*.

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 4 / 43

Page 5: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rozbieżności C i C++

Aby sprawić, że kod ten będzie bezbłędny w obu językachmusimy go odrobinę zmodyfikować:

int *wskaznik = (int*) malloc(sizeof(int));

Problem został rozwiązany przy użyciu tzw. rzutowania - co totakiego właściwie jest?

Rzutowanie ma na celu zamierzoną zmianę typu obiektu.

W języku C dostępny był tylko jeden sposób rzutowania:

typ obiekt = (typ) obiekt_innego_typu;

W C++ nadal można używać takiego rzutowania, jest ononazywane ”rzutowaniem w stylu C”.

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 5 / 43

Page 6: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rozbieżności C i C++

Oprócz tego C++ oferuje też ”rzutowanie w stylu funkcyjnym”:

typ obiekt = typ(obiekt_innego_typu);

Oba rzutowania działają dokładnie tak samo.Przedstawione sposoby rzutowania mają jednak istotne wady:

ciężko wypatrzeć je w kodzie,każde takie rzutowanie jest potencjalnym miejscem wystąpieniabłędów,przeglądanie kodu źródłowego w poszukiwaniu rzutowań w stylujęzyka C nie jest łatwe, a przez to i usuwanie błędów zprogramu jest utrudnione.

C++ wprowadza inny system rzutowań - każde z nich od razurzuca się w oczy.

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 6 / 43

Page 7: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Spis treści

1 Geneza rzutowania

2 Rzutowania w języku C++

3 Rzutowanie statyczne

4 Rzutowanie typu const

5 Rzutowanie reinterpretacyjne

6 Rzutowanie dynamiczne

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 7 / 43

Page 8: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowania w języku C++

Rzutowania, które są zalecane w języku C++ podzielono na 4grupy:

static_cast – proste rzutowanie statyczne,

const_cast – rzutowanie pozwalające na zmianęmodyfikatorów const i volatile,

reinterpret_cast – rzutowanie zmieniające sensinterpretacyjny obszaru pamięci zajmowanego przez obiekt,

dynamic_cast – rzutowanie wskaźników do obiektów w trakciewykonywania programu.

Wymienionych operatorów rzutowania używa się w sposób, wjaki zaprezentowano to dla rzutowania statycznego:

typ obiekt = static_cast<typ>(obiekt_innego_typu);

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 8 / 43

Page 9: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowania w języku C++

Powodem wprowadzonego podziału operatorów rzutowania jestpotrzeba zwiększenia bezpieczeństwa przez wyeliminowaniepomyłek.

Dokonanie pewnego rodzaju rzutowania operatorem, który niejest do tego przewidziany spowoduje błąd kompilacji.

Jeśli istnieje podejrzenie, że przyczyną błądu w działaniu programujest rzutowanie, to najczęściej chodzi o jego konkretnego rodzaj -

podział rzutowań ułatwia zatem odnajdywanie takich błędów.

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 9 / 43

Page 10: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Spis treści

1 Geneza rzutowania

2 Rzutowania w języku C++

3 Rzutowanie statyczne

4 Rzutowanie typu const

5 Rzutowanie reinterpretacyjne

6 Rzutowanie dynamiczne

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 10 / 43

Page 11: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowania statyczne

Operator static_cast zapewnia wysoki poziom bezpieczeństwa- ten typ rzutowania gwarantuje możliwie sensowny rezultatrzutowania, zmieniając w razie potrzeby reprezentację bitowąobiektu poddanego rzutowaniu.

Przykładowo przy rzutowaniu zmiennej typu int na double,bity wewnętrznej reprezentacji liczby zostaną zmienione tak, abyreprezentowały tę samą wartość matematyczną, ale wedługformatu używanego dla double.

int myInt = 7;double myDbl = static_cast<double>(myInt);

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 11 / 43

Page 12: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Bardzo prosty przykład

#include <iostream>using namespace std;int main() {int liczba1 = 5, liczba2 = 2;cout << "5/2 bez rzutowania: "

<< liczba1/liczba2 << std::endl;cout << "5/2 static_cast<float>: "

<< static_cast<float>(liczba1) /static_cast<float>(liczba2) << std::endl;

return 0;}

5/2 bez rzutowania: 25/2 static cast<float>: 2.5

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 12 / 43

Page 13: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Bardzo prosty przykład błędnego rzutowania

Poniższy kod programu nie zostanie skompilowany poprawnie zewzględu na brak odpowiedniej konwersji string → char*

#include <iostream>using namespace std;int main() {string str = "ciąg";cout << "string --> char: "

<< static cast<char*>(str)<< endl;

return 0;}

Konwersja taka byłaby nielogiczna.

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 13 / 43

Page 14: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Przykład rzutowania obiektów klas

#include <iostream>using namespace std;

class wektor;class punkt{ public:double x, y;punkt(double x0 = 0., double y0 = 0.):

x(x0), y(y0){}punkt(wektor&);

};class wektor{ public:punkt p1, p2;wektor(punkt p10, punkt p20): p1(p10), p2(p20){}

};

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 14 / 43

Page 15: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Przykład rzutowania obiektów klas

int main(){int i = -7.;double d = static_cast<double>(i);cout << "d= " << d << endl;punkt p(-2., 2.);wektor w = static cast<wektor>(p);cout << "p= " << w.p2.x << ", " << w.p2.y << endl;

return 0;}

Czegoś tu jeszcze brakuje.

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 15 / 43

Page 16: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Przeznaczenie rzutowania statycznego

Operator static_cast służy w szczególności do:

konwersji typów podstawowych, np. int, double czy char,

konwersji zdefiniowanych przez użytkownika,

#include <iostream>using namespace std;class figura{};class odcinek{ public:odcinek(figura& f){} // konstruktor konwertujący

};class trojkat : public figura{public:trojkat(odcinek& o){} // konstruktor konwertujący

};

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 16 / 43

Page 17: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Przeznaczenie rzutowania statycznego

int main() {// Typy predefiniowanechar c = static_cast<char>(65); // brak wymagańcout << c << endl; // litera Achar c1 = static_cast<char>(65.23); // brak wymagańcout << c1 << endl; // również litera A

// Obiekty klasfigura f;// wymagany konstruktor: figura --> odcinekodcinek o = static_cast<odcinek>(f);// wymagany konstruktor: odcinek --> trojkattrojkat t = static_cast<trojkat>(o);

return 0;}Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 17 / 43

Page 18: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Przeznaczenie rzutowania statycznego

Operator static_cast służy również do:

konwersji wskaźnika obiektów klasy pochodnej na wskaźniki doobiektów klasy podstawowej - rzutowanie w górę hierarchiidziedziczenia,

konwersji wskaźnika obiektów klasy podstawowej na wskaźnikiobiektów klasy pochodnej - rzutowanie w dół hierarchii.

// Wskaźniki do obiektów klas ustawionych w hierarchię -// brak wymagań co do konstruktora kopiującegotrojkat *wt;// w górę hierarchiifigura *wf = static_cast<figura*>(wt);// w dół hierarchiitrojkat *wtt = static_cast<trojkat*>(wf);

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 18 / 43

Page 19: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Czego nie może rzutowanie statyczne

Rzutowanie statyczne nie nadaje się do konwersji wskaźnikówróżnych typów, jeśli nie ma specjalnie zdefiniowanej konwersjimiędzy tymi wskaźnikami.

Przykładowo konwersja typu unsigned int → int jestzdefiniowana, a unsigned int* → int* nie.

unsigned int ui;int i = static_cast<int>(ui);unsigned int *wui;int *wi = static cast <int*>(wui);

Rzutowanie statyczne nie nadaje się również do dynamicznejoceny szans powodzenia rzutowania w czasie realizacji programu- wynik działania static_cast jest ustalany w czasie kompilacji.

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 19 / 43

Page 20: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Inne cechy rzutowania statycznego

Standard języka stwierdza również, że wyrażenia, które niedokonują żadnej konwersji mogą być również opisane operatoremstatic_cast, np.:

int i = static_cast<int>(8);

Taka instrukcja może być bezpiecznie usunięta z kodu, ale niezawsze.

W przypadku kodu generycznego, korzystającego z szablonów,należy uważać na usuwanie tego typu instrukcji.

UWAGA:Wszystko co w kontekście rzutowania statycznego powiedziano

dotychczas o wskaźnikach dotyczy również referencji

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 20 / 43

Page 21: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Przeznaczenie rzutowania statycznego

Operator static_cast służy zatem również do:

konwersji referencji do obiektów klasy pochodnej na referencjedo obiektów klasy podstawowej,

konwersji referencji obiektów klasy podstawowej na referencjeobiektów klasy pochodnej.

trojkat t;trojkat& rt = t;

// Referencje do obiektów dowolnych klasodcinek& ro = static cast<odcinek&>(rt);

// Referencje do obiektów klas ustawionych w hierarchię// brak konieczności definiowania konwersjifigura& rf = static_cast<figura&>(rt);trojkat& rtt = static_cast<trojkat&>(rf);

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 21 / 43

Page 22: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Spis treści

1 Geneza rzutowania

2 Rzutowania w języku C++

3 Rzutowanie statyczne

4 Rzutowanie typu const

5 Rzutowanie reinterpretacyjne

6 Rzutowanie dynamiczne

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 22 / 43

Page 23: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie const cast

Rzutowanie const cast służy do nadawania bądź zdejmowaniakwalifikatorów kwalifikatorów const i volatile.

int main(){int intVal = 22;const int *constInt = &intVal;int *tmpInt = const_cast<int*>(constInt);*tmpInt = -1;constInt = const_cast<const int*>(tmpInt);cout << "constInt = " << *constInt;return 0;

}

ci = -1

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 23 / 43

Page 24: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie const cast

Oba kwalifikatory traktowane są tym samym typem rzutowaniaconst cast - nie ma oddzielnego rzutowania dla volatile.

int main(){double dblVal = -11;volatile double *dblVola = &dblVal;

// volatile double ---> doubledouble *dbl = const_cast<double*>(dblVola);

// double ---> volatile doubledblVola = const_cast<volatile double*>(dbl);return 0;

}

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 24 / 43

Page 25: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie const cast

Typ parametru funkcji i typ wyrażenia, które ma go zastąpić mogąsię różnić jedynie pod względem stojących przy nich kwalifikatorówconst i volatile.

Czasami istnieje konieczność dopasowania wskaźników typupoprzez dodanie lub usunięcie tych kwalifikacji.

W wyniku działania operatora const_cast wyrażenia Rvaluezmieniają swoją kwalifikację.

Tak jak dla rzutowania statycznego, typ w nawiasach ostrych jesttypem odniesienia – zazwyczaj jest to typ oczekiwanego wyniku, czylipowinien być zgodny z typem Lvalue .

int ia;const int *pic = const_cast<const int*>(&ia);volatile int *piv = const_cast<volatile int*>(&ia);

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 25 / 43

Page 26: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie const cast

Typ podstawowy obiektów: rzutowanego i tego na któryrzutowanie ma miejsce muszą być identyczne - mogą się różnićjedynie stojącymi przy nich kwalifikatorami const i volatile.

int ia;long la;const int *pid = const_cast<const int*>(&ia);const int *pid = const cast<const int*>(&la);

Typ, na który rzutujemu, musi być wyrażony przez wskaźnik lubreferencję - sam obiekt odpada.

TYP obiekt;TYP* rzut = const_cast<const TYP*>(&obiekt);TYP& rzut = const_cast<const TYP&>(obiekt);TYP rzut = const cast<const TYP>(obiekt);

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 26 / 43

Page 27: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Przykłady rzutowania const cast

#include <iostream>using namespace std;struct mojTyp {int i;mojTyp(): i(3){}void f(int v) const{this->i = v;

// błąd kompilacji: wskaźnik this dla metod typu const// jest również wskaźnikiem typu: const mojTyp*

const_cast<mojTyp*>(this)->i = v;// Tym razem OK - const_cast<mojTyp*>(this) jest// już typu mojTyp*, czyli bez const}

};Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 27 / 43

Page 28: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Przykłady rzutowania const cast

int main() {int i = 3; // i nie jest typu constconst int& rci = i; // ale referencja rci jestrci = 4; // więc błąd kompilacji

// Modyfikacja rci poprzez zastosowane rzutowanieconst_cast<int&>(rci) = 4; // tym razem OKcout << "i = " << i << endl; // wynik: i = 4

// Definicja obiektu klasy mojTyp bez przydomka constmojTyp t;t.f(7);cout << "t.i = " << t.i << endl; // wynik: t.i = 7

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 28 / 43

Page 29: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie const cast

// Definicja wskaźnika do metody klasy mojTypvoid (mojTyp::*pmf)(int) const = &mojTyp::f;

const cast<void(mojTyp::*)(int)>(pmf);// Błąd kompilacji - rzutowanie const_cast nie ma// zastosowania do wskaźników funkcji}

i = 4t.i = 7

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 29 / 43

Page 30: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie const cast

Kwalifikacja wskaźników na przykładzie typu double

Wskaźnik Nazwa mod move

double* wsk zwykły tak tak

const double* wsk do obiektu stałego nie tak

double* const wsk stały tak nie

const double* const wsk stały do obiektustałego

nie nie

mod - modyfikacja obiektów

move - możliwość przesuwania wskaźnika

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 30 / 43

Page 31: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie const cast

int main(){double d1, d2;

// Wskaźnik do obiektu stałegoconst double* cd;cd = &d1; // możliwość zmiany adresu*cd = 1.37; // brak możliwości podstawienia

// Stały wskaźnik do obiektu stałegoconst double* const ccd1;// wymagana inicjalizacja adresuconst double* const ccd1 = &d1;ccd = &wd1; // brak możliwości zmiany adresu*ccd = 2.85; // brak możliwości podstawienia

// Zdjęcie zakazu zmiany adresu i wartości z ccd1double* wd = const_cast<double*>(ccd1);wd = &d2;d2 = 3.85;

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 31 / 43

Page 32: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie const cast

// Nowy stały wskaźnik do obiektu stałegoconst double* const ccd2 =const_cast<const double* const>(wd);

ccd2 = &wd1; // brak możliwości zmiany adresu*ccd2 = 2.85; // brak możliwości podstawienia

// Wypisanie wartości wskazywanej przez ccd2cout << "ccd2 = " << *ccd2;

return 0;}

ccd2 = 3.85

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 32 / 43

Page 33: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Spis treści

1 Geneza rzutowania

2 Rzutowania w języku C++

3 Rzutowanie statyczne

4 Rzutowanie typu const

5 Rzutowanie reinterpretacyjne

6 Rzutowanie dynamiczne

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 33 / 43

Page 34: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie reinterpret cast

Operator reinterpret cast służy do rzutowania wskaźników nazmienne typu całkowitego lub do zamiany typu wskaźników.

Jeżeli wskaźnik wskazuje na komórki pamięci jednego typu (np.float), a chcemy zapisać wskazywany adres do wskaźnikainnego typu (np. int) to należy użyć właśnie tego operatora:

float *wf = new float;// zmienna typu float zajmuje 4 bajty pamięci*wf = 33.2;int *wi = reinterpret_cast<int*>(wf);// zmienna int zajmuje również 4 bajty pamięcicout << "float: " << *wf << " ---> int: " << *wi << endl;// ten sam układ bitów, ale inna interpretacja

float: 33.2 ---> int: 1107610829

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 34 / 43

Page 35: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie reinterpret cast

Jego działanie w standardzie C++03 jest identyczne zrzutowaniem starego typu.

Jednak podobnie jak wcześniej omawiane operatory łatwo możeon być odnaleziony w tekście i użyty do konwersji pomiędzywskaźnikiem, a typem całkowitym.

int adres = 0x0f6a2f1;double dbl = 1;// ustawienie wskaźnika na adresint *wsk = reinterpret_cast<int*>(adres);cout << "Wskaźnik wsk wskazuje na: " << wsk << endl;// przypisanie wskaźnikowi nowego adresuwsk = reinterpret_cast<int*>(&dbl);cout << "Teraz wsk wskazuje na: " << wsk << endl;

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 35 / 43

Page 36: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie reinterpret cast

Konwersja pomiędzy wskaźnikiem, a typem całkowitym wydaje siębyć najbardziej sensownym zastosowaniem tego operatora.

Operator reinterpret_cast pozwala także na konwersjewskaźnika char* do typu całkowitego - to sposób na zapamiętanieadresu tablicy znakowej.

int main(){const char *str = "To moj string";long int s_addr = reinterpret_cast<long int>(str);cout << "Napis \"" << str

<< "\" znajduje sie pod adresem " << s_addr;return 0;

}

Napis "To moj string" znajduje sie pod adresem 4714532

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 36 / 43

Page 37: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Spis treści

1 Geneza rzutowania

2 Rzutowania w języku C++

3 Rzutowanie statyczne

4 Rzutowanie typu const

5 Rzutowanie reinterpretacyjne

6 Rzutowanie dynamiczne

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 37 / 43

Page 38: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie dynamic cast

Operator dynamic_cast służy do konwersji wskaźników ireferencji klas podstawowych na ich odpowiedniki dla klaspochodnych (w dół hierarchii dziedziczenia) oraz odwrotnie (wgórę hierarchii) w trakcie wykonywania programu.

struct Base{virtual ~Base(){}};struct Deriv : public Base{};int main(){Deriv *wd = new Deriv;Base *wb = dynamic_cast<Base*>(wd); // w góręDeriv *nwd = dynamic_cast<Deriv*>(wb); // w dółBase &rd = *wb;Deriv &rb = dynamic_cast<Deriv&>(rd);return 0;

}

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 38 / 43

Page 39: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie dynamic cast

Możliwość rzutowania w górę ma mniejsze znaczenie, gdyż wtakim przypadku i tak może zajść konwersja automatyczawskaźników klas powiązanych w hierarchię.Rzutowanie w dół wymaga dodatkowo:

publicznego dziedziczenia klas,polimorficzności typów hierarchicznych.

Rzutowanie dynamiczne odbywa się w trakcie wykonywaniaprogramu i ma szczególne zastosowanie wtedy, gdy nie mapewności kompatybilności typów.Przy braku kompatybilności rzutowanie takie nie ma sensu.W razie niekompatybilności dynamic_cast zwróci:

wartość NULL w przypadku rzutowania wskaźników,wyjątek bad cast , w przypadku rzutowania referencji.

Umożliwia sprawdzanie przynależności obiektów do danej klasy.

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 39 / 43

Page 40: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie dynamic cast

Przykład zastosowania:

#include <iostream>using namespace std;struct Base{virtual ~Base(){};};class Deriv : public Base{double saldo = 121.12;

public:double getN(){return saldo;}

};Base* switchFun(bool bas){if (bas) return new Base;else return new Deriv;

}

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 40 / 43

Page 41: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie dynamic cast

int main(){Base *bas = switchFun(false);Deriv *der = dynamic_cast<Deriv*>(bas);cout<< der->getN() << endl;return 0;

}

Ten kod programu spowoduje wypisanie liczby 121.12.

Jednak zmiana wywołania funkcji switchFun(false) naswitchFun(true) spowoduje błąd wykonania choć kompilacjaw obu przypadkach przebiegnie prawidłowo.

Natomiast usunięcie rzutowania dynamic_cast<Deriv*>spowoduje błąd kompilacji, tak więc rzutowanie to jestkonieczne.

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 41 / 43

Page 42: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie dynamic cast

Problem polega na prawidłowym odwołaniu do metody getN()przy pomocy wskaźnika der.

Jeśli temu wskaźnikowi przypisany zostanie wskaźnik typuDeriv, to wszystko jest w porządku - metodę Deriv::getN()może zostać wywołana.

Gdy trafi tam wskaźnik typu Base nastąpi próba odwołania siędo nieistniejącej metody Base::getN() i błąd wykonania.

W takim jednak przypadku wskaźnik der będzie miał wartośćNULL, więc zamiana instrukcji wypisywani na:

if(der) cout<< der->getN() << endl;

rozwiązuje problem błędu wykonania.

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 42 / 43

Page 43: Programowanie Obiektowo Zorientowane w jezyku c++ - Rzutowaniaglowacki/docs/matwykl/O-o/... · C++, lecz istnieje kilkarozbieżnościod tej zasady - jedna z nich dotyczy właśnie

Rzutowanie dynamic cast

W przypadku rzutowania referencji funkcja main musi byćbardziej złożona:

Base& switchFun(bool bas){if (bas) return *new Base;else return *new Deriv;

}int main(){Base &bas = switchFun(true);try {Deriv &der = dynamic_cast<Deriv&>(bas);cout<< der.getN() << endl;

} catch(const bad_cast& e){}return 0;

}

Mirosław Głowacki (AGH, UJK) Programowanie w języku c++ 2016/2020 43 / 43