POwyklad9

background image

Tomasz Marks - Wydział MiNI PW

-1-

Programowanie Obiektowe

(j

ę

zyk C++)

Wykład 9.

Tomasz Marks - Wydział MiNI PW

-2-

OBSŁUGA

WYJ

Ą

TKÓW

Tomasz Marks - Wydział MiNI PW

-3-

Przeciwdziałanie bł

ę

dom wykonania programu (1)

double& Vector :: operator [ ] ( int i )
{

return V[ i ];

// operacja niebezpieczna !!!

}

double& Vector :: operator [ ] ( int i )
{

if ( i >= 0 && i < Size ) return V[ i ];
DisplayMessage( "
komunikat o bł

ę

dzie" );

// fukcja systemowa lub własna

exit(1);

// funkcja standardowa

}

double& Vector :: operator [ ] ( int i )
{

assert ( i >= 0 && i < Size )

// makro assert

return V[ i ];

}

double& Vector :: operator [ ] ( int i )
{

if ( i < 0 || i >= Size ) throw xcp_scope( i ); // odrzucenie wyj

ą

tku

return V[ i ];

}

Tomasz Marks - Wydział MiNI PW

-4-

Przeciwdziałanie bł

ę

dom wykonania programu (2)

// vector.h

struct xcp_memory { };

// zewn

ę

trzna (wzgl. Vector) klasa pomocnicza

class Vector
{

int Size, Nr;
double *V;
static int DefSize, VCounter;
void Init ( int = 0, double = 0, double * = 0 );

public:

Vector ( );
Vector ( int size, double val = 0 );
Vector ( int size, double arr[ ] );

……………………………….

struct xcp_scope

// wewn

ę

trzna (w Vector) klasa pomocnicza

{

int index;
xcp_scope ( int );

};

……………………………….

};

background image

Tomasz Marks - Wydział MiNI PW

-5-

Przeciwdziałanie bł

ę

dom wykonania programu (3)

// vector.cpp

// implementacja konstruktora klasy xcp_scope

Vector :: xcp_scope :: xcp_scope ( int i ) : index ( i ) { }

// metoda prywatna (wersja oryginalna)

void Vector :: Init ( int s, double val, double tab[ ] )
{

Nr = ++VCounter;
if ( s <= 0 ) s = DefSize;
V = new double [ s ];
if ( ! V ) { Size = 0; return; }
Size = s;
for ( s = 0; s < Size; ++s )

V [ s ] = tab ? tab [ s ] : val;

}

Tomasz Marks - Wydział MiNI PW

-6-

Przeciwdziałanie bł

ę

dom wykonania programu (4)

// metoda prywatna (wersja zmodyfikowana)

void Vector :: Init ( int s, double val, double tab[ ] )
{

if ( VCounter > 7 ) throw "Za duzo wektorow!";

Nr = ++VCounter;

if ( s < 0 ) throw "Blad konstrukcji!";

if ( s <= 0 ) s = DefSize;

try
{

V = new double [ s ];

}
catch ( … ) { throw xcp_memory ( ); }
if ( ! V ) throw xcp_memory ( );

Size = s;
for ( s = 0; s < Size; ++s )

V [ s ] = tab ? tab [ s ] : val;

}

Tomasz Marks - Wydział MiNI PW

-7-

Przeciwdziałanie bł

ę

dom wykonania programu (5)

#include "vector.h"

void main ( )
{

Vector w( 4 );

for ( int i = -1; i < 7; i++ )
try {

cout << endl << "i = " << i << " ";
Vector z( i );
w[ i ] = i;
cout << "w[" << i << "] = " << w[ i ];

}
catch ( const char * str )
{ cout << str; }
catch ( xcp_memory )
{ cout << "Brak pamieci"; }
catch ( Vector :: xcp_scope ex )
{ cout << "Odrzucono indeks " << ex.index; }

}

Tomasz Marks - Wydział MiNI PW

-8-

Przeciwdziałanie bł

ę

dom wykonania programu (6)

Program wy

ś

wietli:

i = -1

Blad konstrukcji!

i = 0

w[ 0 ] = 0

i = 1

w[ 1 ] = 1

i = 2

w[ 2 ] = 2

i = 3

w[ 3 ] = 3

i = 4

Odrzucono indeks 4

i = 5

Odrzucono indeks 5

i = 6

Za duzo wektorow!

background image

Tomasz Marks - Wydział MiNI PW

-9-

Obsługa wyj

ą

tków [1]

1.

Składnia instrukcji try-catch:

try

// pocz

ą

tek bloku try

{

…...............
……………
……………

}

// koniec bloku try

catch ( ….. ) { ……… }

// 1. blok catch

catch ( ….. ) { ……… }

// 2. blok catch

.…………………………..
catch ( ….. ) { ……… }

// ostatni blok catch

blok try wraz ze wszystkimi nast

ę

puj

ą

cymi po nim blokami

catch stanowi składniowo jedn

ą

cało

ść

, któr

ą

nazywamy

instukcj

ą

try-catch

Tomasz Marks - Wydział MiNI PW

-10-

Obsługa wyj

ą

tków [2]

2. Bloki catch s

ą

nazywane procedurami obsługi wyj

ą

tków.

3. Ka

ż

da procedura obsługi wyj

ą

tków ma okre

ś

lony typ sytuacji

wyj

ą

tkowej, która j

ą

aktywizuje.

4. Zgłoszenie sytuacji wyj

ą

tkowej (throw) podczas wykonywania

bloku try skutkuje przekazaniem pewnego obiektu do odpowiedniej
procedury obsługi.

5. Dopasowanie wyra

ż

enia throw do procedury obsługi polega na

porównaniu typu warto

ś

ci wyra

ż

enia throw z typami ( parametrów )

okre

ś

lonymi dla kolejnych procedur obsługi.

Tomasz Marks - Wydział MiNI PW

-11-

Obsługa wyj

ą

tków [3]

6. Dopasowanie uznane b

ę

dzie za pomy

ś

lne, je

ż

eli spełniony zostanie

jeden z trzech warunków:

(i) oba typy s

ą ś

ci

ś

le zgodne;

(ii) typ okre

ś

lony dla parametru procedury obsługi jest

publiczn

ą

klas

ą

bazow

ą

klasy obiektu b

ę

d

ą

cego warto

ś

ci

ą

wyra

ż

enia throw;

(iii) mo

ż

liwe jest standardowe przekształcenie typu warto

ś

ci

wyra

ż

enia throw, b

ę

d

ą

cej wska

ź

nikiem, na typ wska

ź

nikowy

parametru procedury.

Po pozytywnym rozpoznaniu jednego z warunków (i), (ii), (iii),

dalsze frazy catch nie b

ę

d

ą

analizowane.

Tomasz Marks - Wydział MiNI PW

-12-

Obsługa wyj

ą

tków [4]

7. Je

ż

eli dopasowanie nie da pozytywnego rezultatu, t.zn.

ż

adna

procedura catch nie zostanie uruchomiona, to dana instrukcja
try-catch b

ę

dzie uznana za zako

ń

czon

ą

i nast

ą

pi sprawdzenie,

czy w aktualnie wykonywanej funkcji jest blok try zawieraj

ą

cy

dan

ą

instukcj

ę

try-catch.

Je

ż

eli taki blok istnieje, to wykonana zostanie próba dopasowania

rozpatrywanygo wyj

ą

tku do wyst

ę

puj

ą

cych po nim procedur obsługi.

Je

ż

eli taki blok nie istnieje, to wykonanie funkcji zostanie zako

ń

czone

i odpowiedni blok b

ę

dzie poszukiwany w funkcji wywołuj

ą

cej t

ę

,

w której został odrzucony wyj

ą

tek itd. itd.

W skrajnym przypadku, je

ż

eli dopasowanie nie zostanie zrealizowane

w obr

ę

bie funkcji main(), obsług

ę

wyj

ą

tku przejmie systemowa procedura

obsługi wyj

ą

tków, która wy

ś

wietli odpowiedni komunikat i zako

ń

czy

działanie programu.

background image

Tomasz Marks - Wydział MiNI PW

-13-

Obsługa wyj

ą

tków [5]

8. Zapis procedury obsługi nie musi zawiera

ć

nazwy przyjmowanego

obiektu (parametru). Nazwa jest konieczna jedynie w sytuacji, gdy

zachodzi rzeczywista potrzeba u

ż

ycia warto

ś

ci tego parametru.

9. Trzykropek pozwala okre

ś

li

ć

procedur

ę

wychwytuj

ą

c

ą

wyj

ą

tki

wszystkich typów.

10. Wewn

ą

trz procedury obsługi (catch) mo

ż

na u

ż

y

ć

frazy throw

z pustym wyra

ż

eniem

throw;

Skutkuje to przekazaniem wyj

ą

tku do zewn

ę

trznego bloku try.

W innych kontekstach u

ż

ycie pustego wyra

ż

enia throw jest bł

ę

dem.

Tomasz Marks - Wydział MiNI PW

-14-

Obsługa wyj

ą

tków [6]

11. Deklaracja funkcji mo

ż

e zawiera

ć

klauzul

ę

, która stanowi

ograniczenie zbioru sytuacji wyj

ą

tkowych zgłaszanych bezpo

ś

rednio

lub po

ś

rednio przez t

ę

funkcj

ę

:

void fun1 ( …….. );

// mo

ż

e zgłasza

ć

dowolne wyj

ą

tki

long fun2 ( …….. ) throw (const char*, xcp_scope&);

// mo

ż

e zgłasza

ć

wyj

ą

tki wymienionych typów

double fun3 ( ….. ) throw ( );

// nie mo

ż

e zgłasza

ć ż

adnych wyj

ą

tków

Naruszenie zadeklarowanej specyfikacji spowoduje bł

ą

d wykonania

programu.

12. Klauzula ograniczenia zbioru sytuacji wyj

ą

tkowych nie jest uwa

ż

ana

za element okre

ś

lenia typu funkcji ( tzn. nie wchodzi w skład

deskryptora funkcji ).

Tomasz Marks - Wydział MiNI PW

-15-

FUNKTORY

Tomasz Marks - Wydział MiNI PW

-16-

Funktory (1)

Definicja:

Funktorem (inaczej obiektem funkcyjnym) nazywamy obiekt

klasy, w której zdefiniowany został operator wywołania funkcji
t.zn.
operator( ).

Uwaga 1:

Korzystanie z obiektu funkcyjnego jest składniowo

identyczne z wywołaniem funkcji, dlatego wsz

ę

dzie tam,

gdzie parametrem funkcji ma by

ć

funkcja dostarczana jako

argument, mo

ż

na u

ż

y

ć

funktora.

background image

Tomasz Marks - Wydział MiNI PW

-17-

Funktory (2)

Zwykł

ą

funkcj

ę

typ funkcja ( argumenty )
{

Tre

ść

Funkcji

}

mo

ż

na "przekształci

ć

" na funktor wg schematu:

class Funktor
{
public:

typ operator ( ) ( argumenty ) const
{

Tre

ść

Funkcji

}

}

funkcja;

Tomasz Marks - Wydział MiNI PW

-18-

Funktory (3)

Uwaga 2:

Funktory s

ą

obiektami klas, w których oprócz operator()

mog

ą

by

ć

zdefiniowane inne metody i pola składowe, w tym

konstruktory. Zatem:

- funktory mog

ą

posiada

ć

stan wewn

ę

trzny, który mo

ż

e by

ć

inicjowany, odczytywany i modyfikowany;

- mo

ż

e jednocze

ś

nie istnie

ć

wiele funktorów (obiektów)

tej samej klasy (realizuj

ą

cych takie same obliczenia),

ale ró

ż

ni

ą

cych si

ę

stanem wewn

ę

trznym;

- w przypadku zwykłych funkcji namiastk

ą

stanu mo

ż

e by

ć

zmienna globalna lub lokalna dla funkcji zm. statyczna.

Tomasz Marks - Wydział MiNI PW

-19-

Funktory (4)

Uwaga 3:

Ka

ż

dy funktor posiada własny typ, co mo

ż

e by

ć

pomocne przy korzystaniu z szablonów:

- funktory b

ę

d

ą

c obiektami ró

ż

nych klas maj

ą

ż

ne typy,

nawet je

ś

li ich operatory wywołania funkcji maj

ą

identyczne

sygnatury;

- zwykłe funkcje o identycznych sygnaturach s

ą

z punktu

widzenia szablonów nierozró

ż

nialne.

Tomasz Marks - Wydział MiNI PW

-20-

Funktory – przykład (1)

#include <iostream>
using namespace std;

class Sum
{

int s;

public:

Sum ( ) : s(0) { }
void operator ( ) ( int a ) { s += a; }
int operator ( ) ( ) { return s; }

};

int arr[ ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, };

void main ( )
{

Sum parzyste, nieparzyste;
for ( int i = 0; i < 10; ++i )

if ( i & 1 ) nieparzyste ( arr[ i ] ); else parzyste ( arr[ i ] );

cout << parzyste() << " " << nieparzyste();

// 25 30

}

background image

Tomasz Marks - Wydział MiNI PW

-21-

Funktory – przykład (2)

#include <iostream>
using namespace std;

class Arr
{

int n, m;
double *A;

public:

Arr ( int i, int j ) : n( i ), m( j ) { A = new double [ n * m ]; }
~Arr ( ) { delete [ ] A; }
double & operator ( ) ( int i, int j ) { return A[ i * m + j ]; }

};

void main ( )
{

Arr A (3, 4);

for ( int i = 0; i < 3; ++i )
for ( int j = 0; j < 4; ++j ) A( i, j ) = 10 * ( i + 1) + ( j + 1 );

for ( int i = 0; i < 3; ++i )
{

cout << endl;
for ( int j = 0; j < 4; ++j ) cout << A( i, j ) << " ";

// 11 12 13 14

}

// 21 22 23 24

}

// 31 32 33 34

Tomasz Marks - Wydział MiNI PW

-22-

KONWERSJE

i KONWERTERY

Tomasz Marks - Wydział MiNI PW

-23-

Klasyfikacja konwersji (klasycznych) (1)

1. Standardowe – mog

ą

by

ć

wykonywane jawnie i niejawnie, np.

- dana typu arytmetycznego lub znakowego -> inna dana typu

arytmetycznego lub znakowego,

- dana reprezentowana literałem 0 lub 0L -> dana wskazuj

ą

ca

dowolnego typu,

- dana dowolnego typu wskazuj

ą

cego -> dana typu void*,

- ………………………………..

2. Definiowalne – mog

ą

by

ć

wykonywane jawnie i niejawnie:

- wszystkie konwersje okre

ś

lone przez konstruktory jednoparametrowe

i konwertery.

3. Dopuszczalne (predefiniowane konwersje, których skutek mo

ż

e zale

ż

e

ć

od implementacji) – musz

ą

by

ć

wykonywane jawnie, np.

- dana całkowita -> dana wyliczeniowa,
- dana typu wskazuj

ą

cego -> dana innego typu wskazuj

ą

cego

(z wył

ą

czeniem przypadku void*),

- dana typu całkowitego <-> dana typu wskazuj

ą

cego,

- wskazanie zmiennej ustalonej (albo ulotnej) -> wskazanie analogicznej

zmiennej nieustalonej (albo nieulotnej),

- ………………………………..

Tomasz Marks - Wydział MiNI PW

-24-

Operatory konwersji (klasyczne)

Dla typu docelowego TYPE operator konwersji jest opisywany
wyra

ż

eniem postaci:

TYPE ( wyr ) , gdzie TYPE - identyfikator typu,

wyr

- konwertowane wyra

ż

enie,

albo

( TYPE ) wyr

, gdzie TYPE - dowolna nazwa typu,

wyr

- konwertowane wyra

ż

enie,

Np.

k = (int) 12.5;

// zapis poprawny

k = int ( 12.5 );

// zapis poprawny

p = (char *) z;

// zapis poprawny

p = char* ( z );

//

Ą

D!

- char* jest nazw

ą

typu

// ale nie jest identyfikatorem

background image

Tomasz Marks - Wydział MiNI PW

-25-

Klasyfikacja konwersji (klasycznych) (2)

1. Konwersje warto

ś

ciowe (nieodno

ś

nikowe, niereferencyjne)

Je

ż

eli typ docelowy nie jest odno

ś

nikowy, to rezultatem konwersji

b

ę

dzie zmienna typu TYPE zainicjowana dan

ą

powstał

ą

z przekształcenia

danej o warto

ś

ci wyr na dan

ą

typu TYPE.

Zmienna taka nie jest L-nazw

ą

.

Np.

double X = 1.5;

//(int) X = 12;

//

Ą

D!

- (int) X nie jest L-nazw

ą

cout << (int) X;

// O.K. - wyprowadzi 1

// rezultatem konwersji jest zmienna tymczasowa,
// któr

ą

mo

ż

na zdefiniowa

ć

instrukcj

ą

: int tmp = 1;

.

Tomasz Marks - Wydział MiNI PW

-26-

Klasyfikacja konwersji (klasycznych) (3)

2. Konwersje odno

ś

nikowe (referencyjne)

Je

ż

eli typ docelowy jest odno

ś

nikowy, to rezultatem konwersji b

ę

dzie

odno

ś

nik typu TYPE zainicjowany argumentem konwersji.

Taki odno

ś

nik

jest L-nazw

ą

tylko wówczas, gdy spełnione s

ą

2 warunki:

(i) wyr jest L-nazw

ą

zmiennej,

(ii) istnieje konwersja &wyr na TYPE*

(konwersja wskazania argumentu na wskazanie typu docelowego).

Np.

const int X = 10;
X = 12

//

Ą

D!

- X ma atrybut const

(int &) X = 20;

// O.K.

int & tmp = *(int *) & X;

// (zmienna tmp skojarzona jest z obszarem
// pami

ę

ci przydzielonym na zmienn

ą

X)

cout << X;

// wyprowadzi 20 albo 10 (

!!!

)

Tomasz Marks - Wydział MiNI PW

-27-

Konwertery (1) - Definicja

Konwerterem

definiowanego typu Class do typu docelowego TYPE

jest bezparametrowa metoda o deklaracji

Class :: operator TYPE ( );

w której TYPE jest nazw

ą

(!) typu nie zawieraj

ą

c

ą

nawiasów.

Wykonanie w ciele konwertera instrukcji

return wyr ;

skutkuje udost

ę

pnienien zmiennej typu TYPE o warto

ś

ci

(TYPE) wyr

UWAGA.

Wymaga si

ę

, by konwersja typu wyra

ż

enia wyr do TYPE istniała.

Tomasz Marks - Wydział MiNI PW

-28-

Konwertery (2) – przykład definiowania

class CMPLX
{

double Re, Im;

public:

CMPLX ( double );

// konwersja double









CMPLX

……………………..
operator double ( );

// konwersja CMPLX









double

operator const char * ( );

// konwersja CMPLX









const char *

……………………..

};

CMPLX :: CMPLX ( double re ) : Re(re), Im(0) { }

CMPLX :: operator double ( ) { return Re; }

CMPLX :: operator const char * ( )
{

if ( Re == 0 && Im == 0 ) return "Zero";
if ( Im == 0 ) return "Real";
if ( Re == 0 ) return "Imag";
return "Cmplx";

}

background image

Tomasz Marks - Wydział MiNI PW

-29-

Konwertery (3) – przykład u

ż

ycia

#include "cmplx.h"
typedef const char * ConstCharPtr;

void main ( )
{

CMPLX X(1.5,2.3), Y(5), Z;
double a, b, c;
const char *A, *B, *C;

a = (double) X;

// jawne u

ż

ycie konwertera na double

b = double (X);

// jawne u

ż

ycie konwertera na double

c = X;

// niejawne u

ż

ycie konwertera na double

cout << a << b << c;

// 1.5 1.5 1.5

A = (const char *) Y;

// jawne u

ż

ycie konwertera na const char *

//A = const char * (Y); //

Ą

D! - const char * nie jest identyfikatorem

B = ConstCharPtr (Y);

// jawne u

ż

ycie konwertera na const char *

C = Y;

// niejawne u

ż

ycie konwertera na const char *

cout << A << B << C;

// Real Real Real

X = (CMPLX) a;

// jawne u

ż

ycie konwersji konstruktorowej

Y = CMPLX (a);

// jawne u

ż

ycie konwersji konstruktorowej

Z = a;

// niejawne u

ż

ycie konwersji konstruktorowej

cout << X << Y << Z;

// [1.5,0] [1.5,0] [1.5,0]

}

Tomasz Marks - Wydział MiNI PW

-30-

"Nowe" operatory konwersji (1)

Obecnie zaleca si

ę

stosowanie "nowych" operatorów konwersji,

zapisywanych z wykorzystaniem słów kluczowych:

static_cast
reinterpret_cast
const_cast
dynamic_cast

U

ż

ycie "nowych" operatorów konwersji ma posta

ć

:

xxxxx_cast < typ_docelowy > ( konwertowane_wyra

ż

enie )

Tomasz Marks - Wydział MiNI PW

-31-

"Nowe" operatory konwersji (2)

static_cast – wykorzystywany do konwersji typów spokrewnionych

- typu zmiennopozycyjny -> typu całkowity,

- typ wyliczeniowy -> typ całkowity,

- typ wska

ź

nikowy -> inny spokrewniony typ wska

ź

nikowy, ……

Np.

int x = static_cast<int>(22.6);

PhVectorB *p = static_cast<PhVectorB*>(Vec);

int *p = static_cast<int*>(malloc(20));

reinterpret_cast

– wykorzystywany do konwersji typów niespokrewnionych

- typ całkowity -> typ wska

ź

nikowy,

- typ wska

ź

nikowy -> inny niespokrewniony typ wska

ź

nikowy, ……

Np.

io_Unit* we = reinterpret_cast<io_Unit*>(0x123e);

Tomasz Marks - Wydział MiNI PW

-32-

"Nowe" operatory konwersji (3)

const_cast – wykorzystywany do usuwania kwalifikatora const

Np.

const int x = 10;

const_cast <int&> ( x ) = 20;

dynamic_cast

– wykorzystywany do konwersji kontrolowanej w czasie

wykonywania programu.

Np.

Zwierz* pZ;

Pies P("Burek");

Ssak D("Umo");

pZ = dynamic_cast <Zwierz*> ( &P );

// pZ = wskazanie na P

pZ = dynamic_cast <Zwierz*> ( &D );

// pZ = 0, je

ś

li niepoprawne

Zwierz& rZ = dynamic_cast <Zwierz&> ( *pZ );

// odrzuci wyj

ą

tek bad_cast, je

ś

li niepoprawne

background image

Tomasz Marks - Wydział MiNI PW

-33-

Koniec wykładu 9.


Wyszukiwarka

Podobne podstrony:
POwyklad2
POwyklad3
POwyklad5
POwyklad10
Pedagogika przewlekle chorych powyklejane, Ważne dla sudenta, Studia pedagogika
POwyklad9
POwyklad2
POwyklad1
POwyklad6
POwyklad4
POwyklad15 planowany
POwyklad4
POwyklad3
POwyklad7
POwyklad15 planowany
POwyklad1
POwyklad6
POwyklad2

więcej podobnych podstron