jp5 print

background image

J˛ezyki programowania – cz˛e´s´c V

Marcin Szpyrka

Katedra Automatyki

Akademia Górniczo-Hutnicza w Krakowie

2009/10

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

1/42

Paradygmaty programowania

Programowanie proceduralne

Zadecyduj, jakie chcesz mie´c procedury; stosuj najlepsze algorytmy, jakie mo˙zesz
znale´z´c.
Programowanie proceduralne polega na tym, by pisz ˛

ac program dla danego

problemu, zamieni´c ten problem na seri˛e zada´n do wykonania, realizowanych przez
funkcje. Wykonywanie takiego programu, to okre´slona sekwencja wywoła´n ró˙znych
funkcji. Wad ˛

a tej techniki programowania jest to, ˙ze zajmuje si˛e ona głównie

funkcjami, a nie dba o to, czy poszczególne dane w programie s ˛

a ze sob ˛

a zwi ˛

azane

czy te˙z rozrzucone w programie w lu´zny sposób.

Programowanie modularne

Zadecyduj, jakie chcesz mie´c moduły; podziel program w taki sposób, aby ukry´c
dane w modułach.
Modułem nazywany jest zbiór powi ˛

azanych ze sob ˛

a procedur, ł ˛

acznie z danymi, na

których te procedury działaj ˛

a.

J˛ezyk C++ dostarcza mechanizm do grupowania zwi ˛

azanych ze sob ˛

a danych,

funkcji, itd. w odr˛ebne przestrzenie nazw.
J˛ezyk C++ wspiera poj˛ecie osobnej kompilacji, mechanizm ten mo˙zna stosowa´c do
tworzenia programu jako zbioru cz˛e´sciowo niezale˙znych fragmentów.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

2/42

background image

Paradygmaty programowania

Programowanie obiektowe

Zadecyduj, jakie chcesz mie´c typy; dla ka˙zdego typu dostarcz pełny zbiór operacji.
W C++ mo˙zna definiowa´c typy (klasy), które b˛ed ˛

a si˛e zachowywa´c (prawie) tak

samo jak typy wbudowane. Powstaje wtedy nie tylko moduł kryj ˛

acy w sobie dane,

ale wr˛ecz nowy typ danej.
Programowanie t ˛

a technik ˛

a cechuje si˛e tym, i˙z danym zgrupowanym w (obiekt) nie

mówi si˛e ju˙z jak maj ˛

a co´s zrobi´c, ale tylko co maj ˛

a zrobi´c. Niedogodno´sci ˛

a tej

techniki jest fakt, ˙ze poszczególne typy danych s ˛

a sobie obce. Znaczy to, ˙ze je´sli

funkcja mo˙ze przyj ˛

a´c jako argument jeden typ danej, to nie mo˙ze przyj ˛

a´c innego. Dla

tego innego typu musi by´c zdefiniowana osobna funkcja, cho´cby jej ciało miało by´c
identyczne jak ju˙z istniej ˛

acej.

Programowanie obiektowo orientowane

Zadecyduj, jakie chcesz mie´c typy; dla ka˙zdego typu dostarcz pełny zbiór operacji;
korzystaj ˛

ac z mechanizmu dziedziczenia, jawnie wska˙z to, co jest wspólne.

Jest to technika obiektowa wzbogacona o dziedziczenie i polimorfizm. Sprawia to, ˙ze
istniej ˛

acy kod potrafi si˛e sam zorientowa´c w trakcie pracy programu z jakim

obiektem w danej chwili pracuje i odpowiednio na to reagowa´c. Tego typu technika
odzwierciedla zale˙zno´sci klas obiektów otaczaj ˛

acych nas w realnym ´swiecie.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

3/42

Paradygmaty programowania

Programowanie uogólnione

Zadecyduj, jakie chcesz mie´c algorytmy; parametryzuj je w taki sposób, by działały
dla ró˙znych typów i struktur danych.
Programowanie uogólnione wi ˛

a˙ze si˛e z wykorzystaniem szablonów (wzorców)

funkcji i klas. Podstawowe zało˙zenie jest takie, je´sli mo˙zna wyrazi´c algorytm
niezale˙znie od szczegółów reprezentacji i mo˙zna to zrobi´c tanio oraz bez logicznych
przeinacze´n, to nale˙zy to zrobi´c.
Szablony s ˛

a mechanizmem czasu kompilacji, nie wprowadzaj ˛

a ˙zadnego narzutu

czasu wykonania w porównaniu z kodem pisanym r˛ecznie.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

4/42

background image

Klasy

Klasa jest kluczow ˛

a koncepcj ˛

a j˛ezyka C++, realizuj ˛

ac ˛

a abstrakcj˛e danych na bardzo

wysokim poziomie. Odpowiednio zdefiniowane klasy udost˛epniaj ˛

a u˙zytkownikowi

wszystkie istotne mechanizmy programowania obiektowego: enkapsulacj˛e,
dziedziczenie, polimorfizm, a tak˙ze szablony klas i funkcji.

Elementami składowymi klasy mog ˛

a by´c struktury danych ró˙znych typów, zarówno

podstawowych, jak i zdefiniowanych przez u˙zytkownika, a tak˙ze funkcje dla
operowania na tych strukturach. Dost˛ep do elementów klasy okre´sla zbiór reguł
dost˛epu.

Klasa jest typem definiowanym przez u˙zytkownika. Deklaracja klasy składa si˛e z:
nagłówka, po którym nast˛epuje ciało klasy, uj˛ete w par˛e nawiasów klamrowych; po
zamykaj ˛

acym nawiasie klamrowym musi wyst ˛

api´c ´srednik. W nagłówku klasy

umieszcza si˛e słowo kluczowe class, a po nim nazw˛e klasy, która od tej chwili staje
si˛e nazw ˛

a nowego typu.

1

class

Point

{

2

public

:

3

int

x

;

4

int

y

;

5

char

name

;

6

7

double

distance

();

8

};

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

5/42

Klasy – przykład

1

#include

<iostream>

2

#include

<cmath>

3

using namespace

std

;

4

5

class

Point

{

// classpoint.cpp

6

public

:

7

int

x

;

8

int

y

;

9

char

name

;

10

11

double

distance

();

12

};

13

14

double

Point

::

distance

()

15

{

16

return

sqrt

(

x

*

x

+

y

*

y

);

17

}

18

19

int

main

()

20

{

21

Point p

= {10, 25,

’A’

};

22

cout

<<

p

.

name

<<

"("

<<

p

.

x

<<

","

<<

p

.

y

<<

")\n"

;

23

return

0;

24

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

6/42

background image

Reprezentacja klas – diagramy klas UML

Klasa jest reprezentowana przez prostok ˛

at z wydzielonymi przedziałami: nazw ˛

a,

atrybutami i operacjami. W celu zwi˛ekszenia czytelno´sci, dowolny z nich mo˙zna
ukry´c b ˛

ad´z doda´c nowy (np. przechowuj ˛

acy zdarzenia lub wyj ˛

atki). Tradycyjnie

nazwa klasy zaczyna si˛e z du˙zej litery, jest pogrubiona, a w przypadku klasy
abstrakcyjnej tak˙ze pochyła.

Ka˙zdy atrybut pokazywany jest przynajmniej jako nazwa, opcjonalnie tak˙ze z typem,
widoczno´sci ˛

a, warto´sci ˛

a domy´sln ˛

a i dodatkowymi ograniczeniami. Do oznaczania

poziomów widoczno´sci u˙zywane b˛ed ˛

a symbole: + (publiczny), # (chroniony), −

(prywatny).

Ka˙zda metoda jest pokazywana przynajmniej jako nazwa, a dodatkowo tak˙ze ze
swoimi parametrami i zwracanym typem. Równie˙z w przypadku metod oznaczane s ˛

a

poziomy widoczno´sci.

+ x : int
+ y : int
+ name : char

+ distance() : double

Point

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

7/42

Deklaracja klasy

Klasa mo˙ze by´c deklarowana:

– Na zewn ˛

atrz wszystkich funkcji programu. Zakres widzialno´sci takiej klasy

rozci ˛

aga si˛e na wszystkie pliki programu.

– Wewn ˛

atrz definicji funkcji. Klas˛e tak ˛

a nazywa si˛e lokaln ˛

a, poniewa˙z jej zakres

widzialno´sci nie wykracza poza zasi˛eg funkcji.

– Wewn ˛

atrz innej klasy, jako klas˛e zagnie˙zd˙zon ˛

a (jej zakres widzialno´sci nie

wykracza poza zasi˛eg klasy zewn˛etrznej).

Przy deklarowaniu składowych obowi ˛

azuj ˛

a nast˛epuj ˛

ace ograniczenia:

– deklarowana składowa nie mo˙ze by´c inicjalizowana w deklaracji klasy;

– nazwy składowych nie mog ˛

a si˛e powtarza´c;

– deklaracje składowych nie mog ˛

a zawiera´c słów kluczowych auto, extern i

register, natomiast mog ˛

a by´c poprzedzone słowem kluczowym static.

Deklaracje elementów składowych klasy mo˙zna poprzedzi´c etykiet ˛

a public:,

protected: lub private:. Domy´slnie przyjmowana jest etykieta private.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

8/42

background image

Regulacja dost˛epu do składowych klasy

– Wyst ˛

apienie etykiety private: oznacza, ˙ze

składowe wyst˛epuj ˛

ace po niej s ˛

a

dost˛epna jedynie dla funkcji składowych
klasy i tzw. funkcji zaprzyja´znionych
klasy, w której s ˛

a zadeklarowane.

– Wyst ˛

apienie etykiety public: oznacza, ˙ze

składowe wyst˛epuj ˛

ace po niej s ˛

a

dost˛epne dla dowolnej funkcji, a wi˛ec
równie˙z takiej, które nie jest zwi ˛

azana z

deklaracj ˛

a danej klasy.

– Wyst ˛

apienie etykiety protected: oznacza,

˙ze składowe wyst˛epuj ˛

ace po niej s ˛

a

dost˛epne jedynie dla funkcji składowych
klasy i tzw. funkcji zaprzyja´znionych
klasy, w której s ˛

a zadeklarowane, a tak˙ze

dla funkcji składowych klas pochodnych.

+ distance() : double

− x : int
− y : int
− name : char

+ getX() : int
+ getY() : int
+ getName() : char
+ setX(i : int) : void
+ setY(i : int) : void
+ setName(c : char) : void

Point

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

9/42

Regulacja dost˛epu do składowych klasy – przykład

1

class

Point

{

2

private

:

3

int

x

;

4

int

y

;

5

char

name

;

6

7

public

:

8

int

getX

();

9

int

getY

();

10

char

getName

();

11

void

setX

(int

i

);

12

void

setY

(int

i

);

13

void

setName

(char

c

);

14

double

distance

();

15

};

+ distance() : double

− x : int
− y : int
− name : char

+ getX() : int
+ getY() : int
+ getName() : char
+ setX(i : int) : void
+ setY(i : int) : void
+ setName(c : char) : void

Point

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

10/42

background image

Składowe klasy

z Zakres widzialno´sci składowych obejmuje cały blok deklaracji klasy, bez

wzgl˛edu na to, w którym miejscu bloku znajduje si˛e ich punkt deklaracji.

z Je˙zeli klasa zawiera funkcje składowe, to ich deklaracje musz ˛

a wyst ˛

api´c w

deklaracji klasy. Funkcje składowe mog ˛

a by´c jawnie deklarowane ze słowami

kluczowymi: inline, static i virtual; nie mog ˛

a by´c deklarowane ze słowem

kluczowym extern.

z W deklaracji klasy mo˙zna równie˙z umieszcza´c definicje krótkich (1-2

instrukcje) funkcji składowych; s ˛

a one wówczas traktowane przez kompilator

jako funkcje rozwijalne, tj. tak, jakby były poprzedzone słowem kluczowym
inline.

z Funkcje składowe klasy mog ˛

a operowa´c na wszystkich zmiennych składowych,

tak˙ze prywatnych i chronionych. Mog ˛

a one równie˙z operowa´c na zmiennych

zewn˛etrznych w stosunku do definicji klasy.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

11/42

Definicja klasy

z W programach jednoplikowych dłu˙zsze funkcje składowe deklaruje si˛e w

nawiasach klamrowych zawieraj ˛

acych deklaracj˛e klasy, za´s definiuje si˛e je

bezpo´srednio po zamykaj ˛

acym nawiasie klamrowym.

z Deklaracja klasy wraz z definicjami funkcji składowych stanowi definicj˛e klasy.
z Najcz˛e´sciej definicj˛e klasy umieszcza si˛e w dwóch plikach. W pliku

nagłówkowym (z rozszerzeniem .h) umieszcza si˛e deklaracj˛e klasy, a w pliku

´zródłowym (z rozszerzeniem .cpp) umieszcza si˛e definicj˛e funkcji składowych

klasy. Plik nagłówkowy nale˙zy doł ˛

aczy´c do pliku ´zródłowego korzystaj ˛

ac z

dyrektywy #include.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

12/42

background image

Definicja klasy – przykład (plik point.h)

1

#ifndef

POINT_H

2

#define

POINT_H

3

4

class

Point

{

5

private

:

6

int

x

;

7

int

y

;

8

char

name

;

9

10

public

:

11

int

getX

() { return

x

; }

12

int

getY

() { return

y

; }

13

char

getName

() { return

name

; }

14

void

setX

(int

i

) {

x

=

i

; }

15

void

setY

(int

i

) {

y

=

i

; }

16

void

setName

(char

c

) {

name

=

c

; }

17

double

distance

();

18

};

19

20

#endif

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

13/42

Definicja klasy – przykład (pliki point.cpp i classpoint2.cpp)

1

#include

"point.h"

2

#include

<cmath>

3

4

double

Point

::

distance

()

5

{

6

return

sqrt

(

x

*

x

+

y

*

y

);

7

}

8

9

------------------------------------------------

10

11

#include

<iostream>

12

#include

"point.h"

13

using namespace

std

;

14

15

int

main

()

16

{

17

Point p

;

18

p

.

setX

(20);

19

p

.

setY

(50);

// p.y = 50;

nielegalne

20

p

.

setName

(

’P’

);

21

cout

<<

p

.

getName

() <<

"("

<<

p

.

getX

()

22

<<

","

<<

p

.

getY

() <<

")\n"

;

23

return

0;

24

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

14/42

background image

Wska´znik this

Funkcje składowe s ˛

a zwi ˛

azane z definicj ˛

a klasy, a nie z deklaracjami obiektów tej

klasy. Poci ˛

aga to za sob ˛

a nast˛epuj ˛

ace konsekwencje:

– Istnieje tylko jeden „egzemplarz” kodu definicji danej funkcji składowej,

b˛ed ˛

acej „własno´sci ˛

a” klasy.

– Kod ten nie wchodzi w skład ˙zadnego obiektu.
– W ka˙zdym wywołaniu funkcji składowej klasy musi by´c wskazany obiekt

wołaj ˛

acy.

Wskazanie obiektu wołaj ˛

acego jest realizowane przez przekazanie do funkcji

składowej ukrytego argumentu aktualnego, którym jest wska´znik do tego obiektu.
Wska´znikiem tym jest inicjalizowany niejawny argument – wska´znik – w definicji
funkcji składowej. Do wska´znika tego mo˙zna si˛e równie˙z odwoływa´c jawnie,
u˙zywaj ˛

ac słowa kluczowego this.

1

class

Niejawna

{

2

private

:

3

int

m

;

4

public

:

5

int

funkcja

()

6

{ return

m

; }

7

};

1

class

Jawna

{

2

private

:

3

int

m

;

4

public

:

5

int

funkcja

()

6

{ return this->

m

; }

7

};

W praktyce jawnych odwoła´n do wska´znika this nie opłaca si˛e u˙zywa´c (poza
kilkoma sytuacjami wyj ˛

atkowymi).

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

15/42

Konstruktory i destruktory

Konstruktory i destruktory nale˙z ˛

a do grupy specjalnych funkcji składowych. Grupa ta

obejmuje: konstruktory i destruktor, konstruktor kopiuj ˛

acy oraz operator przypisania.

Konstruktor jest funkcj ˛

a składow ˛

a o takiej samej nazwie, jak nazwa klasy. Nazw ˛

a

destruktora jest nazwa klasy, poprzedzona znakiem tyldy (

). Ka˙zda klasa zawiera

konstruktor i destruktor, nawet gdy nie s ˛

a one jawnie zadeklarowane. Je˙zeli w klasie

nie zadeklarowano konstruktora i destruktora, to zostan ˛

a one wygenerowane przez

kompilator i automatycznie wywoływane podczas tworzenia i destrukcji obiektu.

Konstruktor jest specjaln ˛

a funkcj ˛

a składow ˛

a. W trakcie definiowania obiektu,

przydziela mu si˛e miejsce w pami˛eci, a nast˛epnie (automatycznie) uruchamiany jest
jego konstruktor. Konstruktor sam nie przydziela pami˛eci na obiekt, mo˙ze j ˛

a jedynie

zainicjalizowa´c.

Destruktor jest wywoływany automatycznie zawsze, gdy obiekt jest likwidowany.
Klasa nie musi mie´c obowi ˛

azkowo destruktora. Destruktor nie likwiduje obiekt ani

nie zwalnia obszaru pami˛eci, który obiekt zajmował. Destruktor przydaje si˛e wtedy,
gdy przed zniszczeniem obiektu trzeba jeszcze dokona´c jakich´s działa´n.
Destruktor jest potrzebny, gdy konstruktor danej klasy dokonał na swój u˙zytek
rezerwacji dodatkowej pami˛eci (operatorem new). Wtedy w destruktorze umieszcza
si˛e instrukcj˛e delete zwalniaj ˛

ac ˛

a pami˛e´c.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

16/42

background image

Konstruktory – przykład

1

class

Point

{

2

private

:

3

int

x

;

4

int

y

;

5

char

name

;

6

7

public

:

8

Point

();

9

Point

(int

x

, int

y

, char

c

=

’P’

);

10

Point

(const

Point

&

p

);

11

12

int

getX

() { return

x

; }

13

int

getY

() { return

y

; }

14

char

getName

() { return

name

; }

15

void

setX

(int

i

) {

x

=

i

; }

16

void

setY

(int

i

) {

y

=

i

; }

17

void

setName

(char

c

) {

name

=

c

; }

18

double

distance

();

19

};

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

17/42

Konstruktory – przykład

1

Point

::

Point

()

2

{

3

x

=

y

= 0;

4

name

=

’P’

;

5

}

6

7

Point

::

Point

(int

x

, int

y

, char

c

)

8

{

9

this

->

x

=

x

;

10

this

->

y

=

y

;

11

name

=

c

;

12

}

13

14

Point

::

Point

(const

Point

&

p

)

15

{

16

x

=

p

.

x

;

17

y

=

p

.

y

;

18

name

=

p

.

name

;

19

}

20

21

Point p1

(10, 10,

’A’

);

// lub Point p1 = Point(10, 10, ’A’);

22

Point p2

=

Point

();

// Point p2(); to nie to samo

23

Point p3

;

24

Point p4

(

p1

);

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

18/42

background image

Cechy konstruktorów

– Konstruktor mo˙ze by´c przeładowany.

– Konstruktor nie ma wyspecyfikowanego ˙zadnego typu warto´sci zwracanej, nie

zwraca nic - nawet typu void!

– Nie mo˙zna posłu˙zy´c si˛e adresem konstruktora.

– Konstruktor jest wywoływany przy tworzeniu obiektów chwilowych.

– W przypadku obiektów globalnych, których zakres wa˙zno´sci obejmuje cały

plik, konstruktor takiego obiektu jest uruchamiany na samym pocz ˛

atku, jeszcze

przed uruchomieniem funkcji głównej (main).

– Konstruktory i destruktory nie s ˛

a dziedziczone.

– Parametrami formalnymi konstruktora nie mog ˛

a by´c obiekty własnej klasy.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

19/42

Konstruktory i destruktory – przykład

1

class

Vector

{

2

private

:

3

double *

data

;

4

int

size

;

5

6

public

:

7

Vector

();

8

Vector

(int

size

, int

ini

= 0);

9

Vector

(const

Vector

&

source

);

10

~

Vector

();

11

double

getItem

(int

i

);

12

int

setItem

(int

i

, double

x

);

13

int

getSize

();

14

};

− data : double*
− size : int

+ Vector()
+ Vector(size : int, ini : int = 0)
+ Vector(source : const Vector)
+ ~Vector()
+ getItem(i : int) : double
+ setItem(i : int, x : double) : int
+ getSize() : int

Vector

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

20/42

background image

Konstruktor domniemany

Konstruktor domniemany jest to konstruktor, który mo˙ze by´c wywołany bez
argumentów. W klasie mo˙ze istnie´c tylko jeden konstruktor domniemany. Mo˙ze by´c
to konstruktor nie maj ˛

acy argumentów lub maj ˛

acy wszystkie argumenty

domniemane. Je´sli klasa nie ma ˙zadnego konstruktora, to wygenerowany zostanie
automatycznie konstruktor domniemany (public).

1

Vector

::

Vector

()

2

{

3

size

= 0;

4

data

= 0;

5

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

21/42

Konstruktor kopiuj ˛

acy (inicjalizator kopiuj ˛

acy)

Konstruktor kopiuj ˛

acy jest to konstruktor, który mo˙zna wywoła´c z jednym

argumentem, b˛ed ˛

acym referencj ˛

a do danej klasy.

Konstruktor kopiuj ˛

acy mo˙zna wywoła´c jawnie, gdy chcemy utworzy´c obiekt na wzór

innego obiektu danej klasy. Niejawne wywołanie konstruktora kopiuj ˛

acego nast˛epuje

gdy:

– Podczas przesłania argumentów do funkcji, je´sli argumentem funkcji jest obiekt

klasy x przesyłany przez warto´s´c.

– Podczas, gdy funkcja jako swój rezultat zwraca przez warto´s´c obiekt klasy x.

To, co stoi przy instrukcji return, staje si˛e wzorcem do inicjalizacji obiektu
chwilowego b˛ed ˛

acego warto´sci ˛

a tej funkcji. Ten chwilowy obiekt nie jest ju˙z

lokalny – jest widziany z zewn ˛

atrz, z zakresu z którego funkcj˛e wywołali´smy.

1

Vector

::

Vector

(const

Vector

&

source

)

2

{

3

this

->

size

=

source

.

size

;

4

data

= new double[

size

];

5

for

(int

i

= 0;

i

<

size

; ++

i

)

data

[

i

] =

source

.

data

[

i

];

6

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

22/42

background image

Cechy destruktora

– Destruktor jako funkcja nie mo˙ze zwraca´c ˙zadnej warto´sci (nawet typu void).

– Destruktor nie jest wywoływany z ˙zadnymi argumentami. W zwi ˛

azku z tym nie

mo˙ze by´c tak˙ze przeładowany.

– Destruktor jest automatycznie wywoływany, gdy obiekt automatyczny lub

chwilowy wychodzi ze swojego zakresu wa˙zno´sci.

– Destruktor mo˙zna wywoła´c jawnie: obiekt.∼klasa();.

1

Vector

::~

Vector

()

2

{

3

if

(

data

) delete []

data

;

4

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

23/42

Rodzaje polimorfizmu

W´sród zdefiniowanych w j˛ezyku C++ operatorów wyst˛epuj ˛

a operatory

polimorficzne. Wyró˙zniamy dwa rodzaje polimorfizmu:

– Koercj˛e, gdy dopuszcza si˛e, ˙ze argumenty operatora mog ˛

a by´c mieszanych

typów. Ten rodzaj polimorfizmu jest charakterystyczny dla operatorów
arytmetycznych: +, -, *, /; np. operator + mo˙ze słu˙zy´c do dodania dwóch liczb
całkowitych, liczby całkowitej do zmiennopozycyjnej, itd.

– Przeci ˛

a˙zenie (przeładowanie) operatora, gdy ten sam symbol operatora stosuje

si˛e w operacjach nie zwi ˛

azanych semantycznie, np.: operatory inicjalizacji i

przypisania, oznaczane s ˛

a symbolem ’=’; symbole ’>>’ oraz ’<<’ zale˙znie od

kontekstu, s ˛

a bitowymi operatorami przesuni˛ecia lub operatorami

wprowadzania/wyprowadzania.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

24/42

background image

Przeładowanie operatorów

W j˛ezyku C++ istnieje mechanizm, który pozwala tworzy´c nowe definicje dla
istniej ˛

acych operatorów. Ogólna posta´c definicji operatora-funkcji jest nast˛epuj ˛

aca:

typ klasa

::

operator@

(

argumenty

){

/* wykonywane operacje */

}

Słowo typ oznacza typ zwracany przez operator – funkcj˛e, słowo klasa jest nazw ˛

a

klasy, w której funkcja definiuj ˛

aca operator jest funkcj ˛

a składow ˛

a, dwa dwukropki

oznaczaj ˛

a operator zasi˛egu, za´s symbol ’@’ jest zast˛epowany przez symbol operatora

(np. =, ==, +, ++, new). Nazwa funkcji definiuj ˛

acej operator składa si˛e ze słowa

kluczowego operator i nast˛epuj ˛

acego po nim symbolu operatora; np. operator+.

Lista operatorów, które mog ˛

a by´c przeładowane

+

/

%

&

|

!

=

<

>

+ =

− =

∗ =

/ =

% =

=

& =

| =

<<

>>

>>=

<<=

==

! =

<=

>=

&&

||

++

−−

,

− > ∗

− >

new

delete

( )

[ ]

Operatory &, *, −, + mog ˛

a by´c przeładowane zarówno w swojej wersji jedno- jak

i dwuargumentowej. Nie mo˙zna wymy´sla´c i przeładowywa´c własnych operatorów.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

25/42

Przeładowanie operatorów – przykład

1

class

Vector

{

// vector.h

2

private

:

3

double *

data

;

4

int

size

;

5

6

public

:

7

Vector

();

8

Vector

(int

size

, int

ini

= 0);

9

Vector

(const

Vector

&

source

);

10

~

Vector

();

11

12

double

getItem

(int

i

);

13

int

setItem

(int

i

, double

x

);

14

int

getSize

() const { return

size

; }

15

16

Vector

& operator=(const

Vector

&

source

);

17

Vector

operator

+(const

Vector

&

x

);

18

Vector

operator

-();

19

friend double operator*(const

Vector

&

x

, const

Vector

&

y

);

20

};

21

22

ostream

& operator<<(

ostream

&

s

,

Vector

&

x

);

23

istream

& operator>>(

istream

&

s

,

Vector

&

x

);

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

26/42

background image

Przeładowanie operatorów – przykład

1

Vector Vector

::operator+(const

Vector

&

x

)

2

{

3

if

(

x

.

size

==

size

)

4

{

5

Vector z

(

x

.

size

);

6

for

(int

i

= 0;

i

<

x

.

size

; ++

i

)

7

{

8

z

.

data

[

i

] =

x

.

data

[

i

] +

data

[

i

];

9

}

10

return

z

;

11

}

12

// else

13

Vector z

;

14

return

z

;

15

}

16

17

Vector Vector

::operator-()

18

{

19

Vector z

=

Vector

(*this);

20

for

(int

i

= 0;

i

<

z

.

size

; ++

i

)

z

.

data

[

i

] = -

z

.

data

[

i

];

21

return

z

;

22

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

27/42

Przeładowanie operatorów – przykład

1

double operator*(const

Vector

&

x

, const

Vector

&

y

)

2

{

3

if

(

x

.

size

==

y

.

size

)

4

{

5

double

s

= 0;

6

for

(int

i

= 0;

i

<

x

.

size

; ++

i

)

s

+=

x

.

data

[

i

] *

y

.

data

[

i

];

7

return

s

;

8

}

9

// else

10

return

-1.0;

11

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

28/42

background image

Przeładowanie operatorów – przykład

1

ostream

& operator<<(

ostream

&

s

,

Vector

&

x

)

2

{

3

int

i

,

j

;

4

j

=

x

.

getSize

();

5

s

<<

"("

;

6

if

(

j

> 0)

// je´

sli s ˛

a współrz˛

edne

7

{

8

for

(

i

= 0;

i

< (

j

- 1); ++

i

)

s

<<

x

.

getItem

(

i

) <<

", "

;

9

s

<<

x

.

getItem

(

j

- 1);

10

}

11

s

<<

")"

;

12

return

s

;

13

}

14

15

istream

& operator>>(

istream

&

s

,

Vector

&

x

)

16

{

17

int

i

,

j

;

18

double

n

;

19

j

=

x

.

getSize

();

20

for

(

i

= 0;

i

<

j

; ++

i

)

21

{

22

s

>>

n

;

23

x

.

setItem

(

i

,

n

);

24

}

25

return

s

;

26

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

29/42

Własno´sci przeci ˛

a˙zonych operatorów

– Operator @ jest zawsze przeci ˛

a˙zany wzgl˛edem klasy, w której jest

zadeklarowana jego funkcja operator@. Zatem w innych kontekstach operator
nie traci ˙zadnego ze swych oryginalnych znacze´n, ustalonych w definicji j˛ezyka.

– Funkcja definiuj ˛

aca operator musi by´c funkcj ˛

a składow ˛

a klasy, albo mie´c co

najmniej jeden argument b˛ed ˛

acy obiektem lub referencj ˛

a do obiektu klasy (poza

funkcjami redefiniuj ˛

acymi operatory new i delete).

– Nie mog ˛

a by´c przeci ˛

a˙zane operatory ’.’, ’.*’, ’::’, ’?:’, ’sizeof’ oraz symbole ’#’

i ’##’.

– Nie jest mo˙zliwa zmiana priorytetu, reguł ł ˛

aczno´sci, ani liczby argumentów

operatora.

– Funkcje definiuj ˛

ace operatory, za wyj ˛

atkiem funkcji operator=(), s ˛

a

dziedziczone.

– Przeci ˛

a˙zany operator nie mo˙ze mie´c argumentów domy´slnych.

– Funkcje: operator=(), operator[](), operator()() i operator− >() nie mog ˛

a by´c

statycznymi funkcjami składowymi; dzi˛eki temu ich pierwsze od lewej
argumenty b˛ed ˛

a l-warto´sciami.

– Funkcja definiuj ˛

aca operator nie mo˙ze posługiwa´c si˛e wył ˛

acznie wska´znikami.

– Operatory: ’=’ (przypisania), ’&’ (pobrania adresu) i ’,’ (przecinkowy) maj ˛

a

predefiniowane znaczenie w odniesieniu do obiektów klas (o ile nie zostały na
nowo zdefiniowane).

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

30/42

background image

Funkcje zaprzyja´znione

Funkcja operatorowa mo˙ze by´c zwykł ˛

a, globaln ˛

a funkcj ˛

a lub funkcj ˛

a składow ˛

a klasy.

Je´sli operator definiujemy jako funkcj˛e składow ˛

a, to ma ona o jeden argument mniej

ni˙z ta sama funkcja napisana w postaci globalnej (ze wzgl˛edu na wska´znik this).
Je˙zeli chcemy, by operator mógł pracowa´c na niepublicznych składnikach klasy, to
musimy zadeklarowa´c j ˛

a jako funkcj˛e zaprzyja´znion ˛

a z klas ˛

a, tzn. we wn˛etrzu

definicji klasy umieszczamy deklaracj˛e tej funkcji poprzedzon ˛

a słowem kluczowym

friend. Funkcja zaprzyja´zniona ma dost˛ep do wszystkich, nawet prywatnych
składników klasy. Funkcja zaprzyja´zniona nie jest składnikiem klasy i nie zawiera
ukrytego wska´znika this. Zasi˛eg funkcji zaprzyja´znionej jest inny ni˙z funkcji
składowych klasy, jest ona widziana w zasi˛egu zewn˛etrznym, tak jak klasa, w której
została zadeklarowana.

1

double operator*(const

Vector

&

x

, const

Vector

&

y

)

2

{

3

if

(

x

.

size

==

y

.

size

)

4

{

5

double

s

= 0;

6

for

(int

i

= 0;

i

<

x

.

size

; ++

i

)

s

+=

x

.

data

[

i

] *

y

.

data

[

i

];

7

return

s

;

8

}

9

// else

10

return

-1.0;

11

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

31/42

Operator przypisania

Inicjalizacj ˛

a zajmuje si˛e konstruktor kopiuj ˛

acy, a przypisaniem operator przypisania.

Jedyn ˛

a sytuacj ˛

a, gdy na widok znaczka ’=’ rusza do pracy konstruktor kopiuj ˛

acy, jest

wyst ˛

apienie tego znaku w linijce definicji obiektu.

Operator przypisania składa si˛e zwykle z dwóch cz˛e´sci. Najpierw nast˛epuje cz˛e´s´c
destruktorowa, po czym nast˛epuje cz˛e´s´c konstruktorowa przypominaj ˛

aca konstruktor

kopiuj ˛

acy. Ostatnia instrukcja oznacza, ˙ze operator przypisania zwraca jako rezultat

referencj˛e do obiektu, który stoi po lewej stronie operatora przypisania. Umo˙zliwia
to kaskadowe ł ˛

aczenie operatora przypisania, np.: a = b = c;

Vector

&

Vector

::operator=(

Vector

&

s

)

Operator przypisania mo˙ze jako argument przyjmowa´c obiekt danej klasy przysłany
przez warto´s´c lub przez referencj˛e.

Je˙zeli takiego operatora nie zdefiniujemy wówczas kompilator postara si˛e o
wygenerowanie swojego operatora przypisania, przypisuj ˛

acego na zasadzie „składnik

po składniku”. S ˛

a sytuacje, gdy automatyczne generowanie mo˙ze si˛e okaza´c

niemo˙zliwe:

– Je˙zeli klasa ma składnik const.
– Je˙zeli klasa ma składnik b˛ed ˛

acy referencj ˛

a.

– Je´sli klasa ma składnik b˛ed ˛

acy obiektem innej klasy i w tej innej klasie operator

przypisania okre´slony jest jako private.

– Je˙zeli klasa ma klas˛e podstawow ˛

a, w której operator= jest typu private.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

32/42

background image

Operator przypisania – przykład

1

Vector

&

Vector

::operator=(const

Vector

&

source

)

2

{

3

if

(this != &

source

)

// sprawdzamy, czy nie ma przypisania x = x

4

{

5

delete

[]

data

;

6

size

=

source

.

size

;

7

data

= new double[

size

];

8

for

(int

i

= 0;

i

<

size

; ++

i

)

data

[

i

] =

source

.

data

[

i

];

9

}

10

return *this;

// operator przypisania zwraca referencj˛

e do obiektu

11

// dla którego został wywołany

12

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

33/42

Przeładowanie operatorów – przykład

1

int

main

()

// vectormain.cpp

2

{

3

int

i

;

4

cout

<<

"Podaj rozmiar wektora a: "

;

5

cin

>>

i

;

6

Vector a

=

Vector

(

i

);

7

cout

<<

"Po utworzeniu obiektu\na: "

<<

a

<<

endl

;

8

cout

<<

"Podaj współrz˛

edne: "

;

9

cin

>>

a

;

10

cout

<<

"Po wczytaniu danych\na: "

<<

a

<<

endl

;

11

Vector b

;

12

cout

<<

"Po utworzeniu obiektu\nb: "

<<

b

<<

endl

;

13

b

=

a

;

14

cout

<<

"Po przypisaniu\nb: "

<<

b

<<

endl

;

15

Vector c

=

Vector

(

a

);

16

cout

<<

"Po utworzeniu obiektu\nc: "

<<

c

<<

endl

;

17

c

=

a

+

b

;

18

cout

<<

"Po obliczeniu sumy\nc: "

<<

c

<<

endl

;

19

c

= -

c

;

20

cout

<<

"Po zmianie znaku\nc: "

<<

c

<<

endl

;

21

Vector d

(

i

+ 1, 2);

22

cout

<<

"Po utworzeniu obiektu\nd: "

<<

d

<<

endl

;

23

cout

<<

"Iloczyn skalarny a * b: "

<<

a

*

b

<<

endl

;

24

cout

<<

"Iloczyn skalarny a * d: "

<<

a

*

d

<<

endl

;

25

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

34/42

background image

Przeładowanie operatorów – podsumowanie

Operatory =, [], (), − > mog ˛

a by´c przeładowane tylko jako niestatyczne funkcje

składowe klasy. W pozostałych przypadkach mo˙zna wybra´c jedn ˛

a z dwóch wersji

przeładowania.
Je´sli operator zmienia obiekt, na którym pracuje, to definiujemy go jako funkcj˛e
składow ˛

a klasy, w innym przypadku jako funkcj˛e globaln ˛

a (ewentualnie

zaprzyja´znion ˛

a z klas ˛

a).

friend

Vector

operator*(int

x

, const

Vector

&

y

);

Je˙zeli chcemy, by w powy˙zszym przykładzie mogła zachodzi´c przemienno´s´c
działania, to musi zdefiniowa´c dwie funkcje globalne o identycznych ciałach:

friend

Vector

operator*(int

x

, const

Vector

&

y

);

friend

Vector

operator*(const

Vector

&

y

, int

x

);

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

35/42

Konwersje

Konwersje jest to dopasowanie typu zmiennej w sytuacji, gdy nie jest on dokładnie
taki jakiego si˛e spodziewano. Konwersje s ˛

a wykonywane niejawnie, gdy:

– W wywołaniu funkcji wyst˛epuje niezgodno´s´c mi˛edzy argumentami formalnymi

i aktualnymi i istnieje jednoznaczna mo˙zliwo´s´c dopasowania argumentów
aktualnych z u˙zyciem konwersji.

– Przy zwracaniu wyniku przez funkcj˛e, gdy warto´s´c w instrukcji return jest

innego typu ni˙z wynika to z definicji funkcji.

– Przy u˙zyciu operatorów, gdy nast˛epuje niezgodno´s´c argumentów.
– W instrukcjach steruj ˛

acych (if, switch, while,...), gdy w wyra˙zeniu umieszczono

warto´sci innego typu ni˙z int.

– W wyra˙zeniach inicjalizuj ˛

acych.

Konwersje mo˙zna wywoła´c równie˙z jawnie. Istniej ˛

a dwie formy zapisu wywołania

konwersji:

– „wywołanie funkcji”, np. n = int(x);
– „rzutowanie”, np. n = (int)x;

Mo˙zliwe jest definiowanie własnych funkcji konwersji dla nowobudowanych klas.
Konwersje mo˙zna zbudowa´c na dwa sposoby: jako konstruktor jednoargumentowy
przekształcaj ˛

acy typ argumentu, na typ własnej klasy oraz jako operator konwersji,

przekształcaj ˛

acy typ klasy do której nale˙zy na inny typ danych.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

36/42

background image

Konwersje – przykład

1

class

Fraction

{

// fraction.h (fraction.cpp, fractionmain.cpp)

2

private

:

3

int

numerator

;

4

int

denominator

;

5

6

void

abridge

();

7

void

sign

();

8

public

:

9

Fraction

();

10

Fraction

(int

a

, int

b

);

11

Fraction

(const

Fraction

&

x

);

12

Fraction

(int

a

);

// ten konstruktor mo˙

zna u˙

zy´

c do konwersji

13

14

Fraction

operator*(const

Fraction

&

x

);

15

Fraction

operator

/(const

Fraction

&

x

);

16

17

friend

std

::

ostream

& operator<<(

std

::

ostream

&

s

,

Fraction

&

x

);

18

friend

std

::

istream

& operator>>(

std

::

istream

&

s

,

Fraction

&

x

);

19

friend

Fraction

operator

+(const

Fraction

&

x

, const

Fraction

&

y

);

20

friend

Fraction

operator

-(const

Fraction

&

x

, const

Fraction

&

y

);

21

};

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

37/42

Konwersje – przykład

1

int

main

()

// fractionmain2.cpp

2

{

3

Fraction u

,

u1

,

u2

;

4

int

i

,

j

;

5

6

cout

<<

"Podaj licznik i mianownik ułamka: "

;

7

cin

>>

u1

;

8

cout

<<

"Podaj licznik i mianownik ułamka: "

;

9

cin

>>

u2

;

10

cout

<<

"Podaj liczb˛

e całkowit ˛

a i: "

;

11

cin

>>

i

;

12

cout

<<

"Podaj liczb˛

e całkowit ˛

a j: "

;

13

cin

>>

j

;

14

15

cout

<<

"i + j: "

<<

i

+

j

<<

endl

;

16

u

=

u1

+

u2

;

17

cout

<<

"u1 + u2: "

<<

u

<<

endl

;

18

u

=

u1

+

i

;

19

cout

<<

"u1 + i: "

<<

u

<<

endl

;

20

u

=

i

+

u2

;

21

cout

<<

"i + u2: "

<<

u

<<

endl

;

22

return

0;

23

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

38/42

background image

Operator konwersji

Deklaracja wewn ˛

atrz klasy

operator float

();

Definicja funkcji konwertuj ˛

acej

1

punkt

::operator float()

2

{

3

return

x

;

4

}

Je˙zeli chcemy dokona´c konwersji na typ wbudowany, to jedyn ˛

a mo˙zliwo´sci ˛

a jest

zdefiniowanie operatora konwersji (Operator konwersji jest dziedziczony).
Je˙zeli chcemy dokona´c konwersji z klasy A na klas˛e B, to staramy napisa´c si˛e
operator konwersji operator B(); w klasie A, a je´sli jest ona niedost˛epna, to
konstruktor konwertuj ˛

acy w klasie B przyjmuj ˛

acy jako argument obiekt klasy A.

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

39/42

Operator konwersji – przykład

1

class

Fraction

{

2

private

:

3

int

numerator

;

4

int

denominator

;

5

6

void

abridge

();

7

void

sign

();

8

public

:

9

Fraction

();

10

Fraction

(int

a

, int

b

);

11

Fraction

(const

Fraction

&

x

);

12

explicit

Fraction

(int

a

);

13

14

Fraction

operator*(const

Fraction

&

x

);

15

Fraction

operator

/(const

Fraction

&

x

);

16

operator int

();

// operator rzutowania na typ int

17

18

friend

std

::

ostream

& operator<<(

std

::

ostream

&

s

,

Fraction

&

x

);

19

friend

std

::

istream

& operator>>(

std

::

istream

&

s

,

Fraction

&

x

);

20

friend

Fraction

operator

+(const

Fraction

&

x

, const

Fraction

&

y

);

21

friend

Fraction

operator

-(const

Fraction

&

x

, const

Fraction

&

y

);

22

};

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

40/42

background image

Operator konwersji – przykład

1

int

main

()

2

{

3

Fraction u1

,

u2

;

4

int

i

,

j

;

5

6

cout

<<

"Podaj licznik i mianownik ułamka: "

;

7

cin

>>

u1

;

8

cout

<<

"Podaj licznik i mianownik ułamka: "

;

9

cin

>>

u2

;

10

cout

<<

"Podaj liczb˛

e całkowit ˛

a i: "

;

11

cin

>>

i

;

12

13

j

= int(

u1

) +

i

;

14

cout

<<

"u1 + i: "

<<

j

<<

endl

;

15

16

j

=

i

+ int(

u2

);

17

cout

<<

"i + u2: "

<<

j

<<

endl

;

18

return

0;

19

}

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

41/42

Składowe statyczne

Składowe statyczne poprzedza si˛e podczas definicji słówkiem static. Statyczne mog ˛

a

by´c zarówno funkcje, jak i pola nale˙z ˛

ace do klasy. Składnik statyczny jest

elementem, który jest powi ˛

azany z klas ˛

a, a nie z obiektem tej klasy. Funkcje

statyczne słu˙z ˛

a do operowania na składnikach statycznych.

1

class

Date

{

2

int

d

,

m

,

y

;

3

static

Date startDate

;

4

public

:

5

Date

(int

d

= 0; int

m

= 0; int

y

= 0);

6

//...

7

static void

setStartDate

(int, int, int);

8

};

9

10

Date

::

Date

(int

d

= 0; int

m

= 0; int

y

= 0)

11

{

12

this

->

d

=

d

?

d

:

startDate

.

d

;

13

this

->

m

=

m

?

m

:

startDate

.

m

;

14

this

->

y

=

y

?

y

:

startDate

.

y

;

15

}

16

17

Date

::

setStartDate

(1,1,2008);

18

myDate

.

setStartDate

(1,1,2008);

Marcin Szpyrka

J˛ezyki programowania – cz˛e´s´c V

42/42


Wyszukiwarka

Podobne podstrony:
Multilayer Composite Print 2
5 Maerchen PRINT
Multilayer Composite Print (3)
pcb pdf, Top Paste Mask Print
Multilayer Composite Print
Multilayer Composite Print
l16 print
Print your own organs[1]
tpd print screeny
jp2 print
2012 AMI wyklad print cz1
6023 print at home original id Nieznany
print (10)
groups34 PRINT
Print Screen+opis
BS 012 Print at Home original

więcej podobnych podstron