Programowanie obiektowe wykład

background image

Programowanie Obiektowe

1

Zakres wykładu

Programowanie obiektowe w C++

Programowanie obiektowe w C#

Projektowanie obiektowe

Różne technologie obiektowe

Język C++ – literatura

Bjarne Stroustrup ”Język C++”, WNT 2002

Stanley B. Lippman, Josee Lajoie ”Podstawy języka C++”, WNT 2001

Specyfikacja standardu języka C++ – „draft” – 2.12.1996

SGI Standard Template Library Programmer’s Guide

http://www.sgi.com/tech/stl/

background image

Programowanie Obiektowe

2

Podstawowe różnice pomiędzy C a C++

Komentarze

1

x = y;

/

stary

mo˙ze by´c wieloliniowy

/

2

y = z;

// nowy

do ko ´nca linii

Deklaracje i definicje

W C++ nie wolno używać niezadeklarowanych funkcji

Szczególnie istotne staje się dbanie o pliki nagłówkowe

Deklaracje wewnątrz funkcji nie muszą występować bezpośrednio po
klamerce otwierającej - mogą pojawiać się wewnątrz kodu

for (int i=0; i<n; i++) ...

background image

Programowanie Obiektowe

3

Podstawowe różnice pomiędzy C a C++

Deklaracje struktur

tworzą „pełnoprawne” typy (nie potrzeba

typedef

):

Przy następującej deklaracji typu:

1

struct DwaPola {

2

int pole1;

3

double pole2;

4

};

w języku C zmienne deklarujemy przez:

1

struct DwaPola x;

a w języku C++ można przez:

1

DwaPola x;

background image

Programowanie Obiektowe

4

Podstawowe różnice pomiędzy C a C++

Referencje (typ &)

zmienne referencyjne – odnośniki do innych zmiennych, muszą być od
razu inicjowane:

1

int x;

2

int &refx = x;

3

double &cos = nazwaStr.nazwaPola

>iJeszczeCos;

„trzeci” sposób przekazywania argumentów do funkcji

w zapisie jak zwykłe przekazanie przez wartość, w działaniu jak
przekazanie adresu do zmiennej

podobne funkcjonowanie jak w przypadku Pascal’owego przekazywania
argumentu przez zmienną

background image

Programowanie Obiektowe

5

Referencje (typ &) - Przykład

W C zawsze przez wartość (wartością może być wskaźnik):

1

void swap(int x, int y)

2

{

3

int z = x;

4

x = y;

5

y = z;

6

}

1

void swap(int

x, int

y)

2

{

3

int z =

x;

4

x =

y;

5

y = z;

6

}

W C++ można tak:

1

void swap(int &x, int &y)

2

{

3

int z = x;

4

x = y;

5

y = z;

6

}

background image

Programowanie Obiektowe

6

Podstawowe różnice pomiędzy C a C++

Domyślne wartości argumentów funkcji

deklaracja

1

Wielomian Pochodna(Wielomian fun, int ktora=1);

definicja

1

Wielomian Pochodna(Wielomian fun, int ktora) {

2

if (ktora>1)

3

return Pochodna(Pochodna(fun, ktora

1));

4

else

5

for (int i=Stopien(fun); i>0; i

−−

)

6

...

7

}

wartość domyślną można podać w definicji o ile nie było deklaracji

jeśli pewien argument ma wartość domyślną, to muszą ją mieć również
kolejne argumenty

background image

Programowanie Obiektowe

7

Strumienie, operatory << i >>

#include <iostream.h>

lub

1

#include <iostream>

2

using namespace std;

Obiekty standardowego wejścia/wyjścia:

cin

,

cout

,

cerr

.

Klasy

istream

,

ostream

,

ifstream

,

ofstream

,

istrstream

, . . .

Przykład:

1

cout <<

"Prosz˛e o warto´s´c x: "

;

2

cin >> x;

3

cout <<

"zmienna x ma warto´s´c"

<< x << endl;

4

char napis[100];

5

cin.getline(napis, 100);

6

cout << napis;

Formatowanie przez metody klas lub manipulatory.

background image

Programowanie Obiektowe

8

Manipulatory i metody

Manipulator

Metoda

showpos

setf(ios_base::showpos)

noshowpos

unsetf(ios_base::showpos)

showbase

setf(ios_base::showbase)

noshowbase

unsetf(ios_base::showbase)

uppercase

setf(ios_base::uppercase)

nouppercase

unsetf(ios_base::uppercase)

showpoint

setf(ios_base::showpoint)

noshowpoint

unsetf(ios_base::showpoint)

boolalpha

setf(ios_base::boolalpha)

noboolalpha

unsetf(ios_base::boolalpha)

unitbuf

setf(ios_base::unitbuf)

nounitbuf

unsetf(ios_base::unitbuf)

internal

setf(ios_base::internal,ios_base::adjustfield)

background image

Programowanie Obiektowe

9

Manipulator

Metoda

left

setf(ios_base::left,ios_base::adjustfield)

right

setf(ios_base::right,ios_base::adjustfield)

dec

setf(ios_base::dec,ios_base::basefield)

hex

setf(ios_base::hex,ios_base::basefield)

oct

setf(ios_base::oct,ios_base::basefield)

fixed

setf(ios_base::fixed,ios_base::floatfield)

scientific

setf(ios_base::scientific,ios_base::floatfield)

resetiosflags(ios_base::fmtflags)

setf(0,flag)

setiosflags(ios_base::fmtflags)

setf(flag)

setbase(int base)

see above

setfill(char_type c)

fill(c)

setprecision(int n)

precision(n)

setw(int n)

width(n)

endl

EOL and flush

ends

EOS and flush

flush

flush()

background image

Programowanie Obiektowe

10

Funkcjonalność iostream i iomanip

1

#include <iostream>

2

#include <iomanip>

3

using namespace std;

4

void main ( )

5

{

6

int i; float f;

7

cin >> i >> f;

// read an integer and a float from stdin

8

cout << i << endl;

// output the integer and goes at the line

9

cout << f << endl;

// output the float and goes at the line

10

cout << hex << i << endl;

// output i in hexa

11

cout << oct << i << dec << i << endl;

// output i in octal and then in decimal

12

cout << showpos << i << endl;

// output i preceded by its sign

13

cout << setbase(16) << i << endl;

// output i in hexa

14

// output i in dec and pad to the left with character

15

// @ until a width of 20

16

// if you input 45 it outputs 45@@@@@@@@@@@@@@@@@@

17

cout << setfill(

’@’

) << setw(20) << left << dec << i << endl;

background image

Programowanie Obiektowe

11

18

// output the same result as the code just above

19

// but uses member functions rather than manipulators

20

cout.fill(

’@’

);

21

cout.width(20);

22

cout.setf(ios_base::left, ios_base::adjustfield);

23

cout.setf(ios_base::dec, ios_base::basefield);

24

cout << i << endl;

25

// outputs f in scientific notation with

26

// a precision of 10 digits

27

cout << scientific << setprecision(10) << f << endl;

28

// change the precision to 6 digits

29

// equivalents to cout << setprecision(6);

30

cout.precision(6);

31

// output f and goes back to fixed notation

32

cout << f << fixed << endl;

33

}

background image

Programowanie Obiektowe

12

Klasy i obiekty

definicja, pola i funkcje (metody)

1

class Wielomian

2

{

3

int st;

4

double

wsp;

5

Wielomian Pochodna(int ktora=1);

6

};

definicje metod

1

Wielomian Wielomian::Pochodna(int ktora)

2

{

3

if (ktora == 1)

4

for (int i=st; i>0; i

−−

)

5

...

6

else return Pochodna().Pochodna(ktora

1);

7

}

background image

Programowanie Obiektowe

13

Modyfikatory dostępu

dostęp do wnętrza klasy (information hiding):

public

,

protected

,

private

1

class Wielomian

2

{

3

private :

4

int st;

5

double

wsp;

6

7

public :

8

int Stopien() {return st;}

9

Wielomian Pochodna(int ktora=1);

10

};

11

Wielomian w;

// deklaracja w zewn ˛etrznej funkcji

12

w.st;

// nie wolno

13

w.Stopien();

// czemu nie

background image

Programowanie Obiektowe

14

Struktury – też klasy

struktury to klasy o publicznym dostępie – w klasach domyślny modyfikator
dostępu to

private

1

struct nazwa

2

{

3

...

4

};

==

1

class nazwa

2

{

3

public :

4

...

5

};

struktury z modyfikatorami dostępu niczym nie różnią się od klas

background image

Programowanie Obiektowe

15

Konstruktory i destruktory

Konstruktory, destruktory, konstruktory kopiujące – tworzą i likwidują
obiekty

konstruktorów może być wiele (różne konteksty), a destruktor zawsze
tylko jeden

konstruktor = metoda o nazwie takiej jak nazwa klasy

destruktor = metoda o nazwie składającej się z tyldy (

~

) i nazwy klasy

konstruktory mogą być prywatne!

cykl życia obiektu

przydzielenie pamięci → konstrukcja → ···

· · · →

destrukcja → zwolnienie pamięci

background image

Programowanie Obiektowe

16

Konstruktory i destruktor klasy wielomianów

1

class Wielomian

2

{

3

private :

4

int st;

5

double

wsp;

6

public :

7

Wielomian Pochodna(int ktora=1);

8

Wielomian();

// Konstruktor

9

Wielomian(int st, double

wsp);

// Konstruktor

10

Wielomian(Wielomian &);

// Konstruktor kopiuj ˛

acy

11

~Wielomian();

// Destruktor

12

};

background image

Programowanie Obiektowe

17

Konstruktory c.d.

1

void DeklaracjeWielomianow(void)

2

{

3

double tab[] = {2, 5, 16, 0, 12, 4};

4

int n = sizeof(tab)/sizeof(

tab);

5

Wielomian w1;

// konstruktor bezargumentowy

6

Wielomian w2(n, tab);

// konstruktor z argumentami

7

Wielomian w3(w2);

// konstruktor kopiuj ˛

acy

8

Wielomian w4 = w2;

// Uwaga! te˙z konstruktor kopiuj ˛

acy

9

...

10

}

Destruktory wołane są automatycznie w odpowiednim czasie – tutaj na
zakończenie funkcji

DeklaracjeWielomianow

.

background image

Programowanie Obiektowe

18

Tablice obiektów

przy inicjowaniu i zwalnianiu pamięci konstruktor (bezargumentowy) jest
wołany dla każdego obiektu z tablicy

dynamiczny przydział pamięci – operatory

new

i

delete

(

delete[]

)

1

int

x = new int[100];

2

int k;

3

scanf(

"%d"

, &k);

4

Wielomian

w = new Wielomian[k];

5

Wielomian

v = new Wielomian(st, wsp);

6

...

7

delete x;

// Bł ˛

ad

nie zwolnimy wszystkiego

8

delete[] w;

// OK

9

delete v;

// OK

background image

Programowanie Obiektowe

19

Implementacje konstruktorów

wewnątrz klasy:

1

class Wielomian

2

{ ... double

wsp; ...

3

Wielomian() {

4

st = 0;

5

wsp = new double[1];

6

wsp = 0;

7

}

8

};

na zewnątrz:

1

Wielomian::Wielomian() {

2

st = 0;

3

wsp = new double[1];

4

wsp = 0;

5

}

background image

Programowanie Obiektowe

20

Implementacje destruktorów

wewnątrz klasy:

1

class Wielomian

2

{

3

...

4

double

wsp;

5

...

6

~Wielomian() { delete[] wsp; }

7

};

na zewnątrz:

1

Wielomian::~Wielomian()

2

{

3

delete[] wsp;

4

}

background image

Programowanie Obiektowe

21

Wskaźnik this

wskaźnik

this

to wskaźnik do obiektu na którym zawołano daną metodę

(do wykorzystania tylko w metodach klas)

1

Wielomian &Wielomian::RazyStala(double stala)

2

{

3

for (int i=0; i<=st; i++)

4

wsp[i]

= stala;

5

return

this;

6

}

7

8

main()

9

{

10

double wsp[] = {3.0, 2.0, 1.0};

11

Wielomian w(sizeof(wsp)/sizeof(

wsp), wsp);

12

w.RazyStala(2).RazyStala(3);

13

Wielomian w2 = w.Pochodna();

14

}

background image

Programowanie Obiektowe

22

Wskaźnik this

„Odkrywanie” pola przykrytego zmienną

1

Wielomian::Wielomian(int st, double

wsp)

2

{

3

this

>st = st;

4

for (int i=0; i<=st; i++)

5

...

6

}

przekazywanie wskaźnika funkcjom zewnętrznym

1

String::String(char

s)

2

{

3

str = new char[strlen(s)+1];

4

strcpy(str, s);

5

stringMgr

>RejestrPamieci(this, s);

6

}

background image

Programowanie Obiektowe

23

Friends czyli przyjaciele

friends – przyjaciele – klasy i funkcje zadeklarowane jako przyjaciele mają

pełen dostęp do prywanych i chronionych pól i funkcji klasy

1

class Wielomian {

2

...

3

friend class PrzestrzenWielomianow;

4

friend Wielomian Dodaj(Wielomian &, Wielomian &);

5

friend void Menedzer::Zarzadzaj(Wielomian &);

6

};

7

Wielomian Dodaj(Wielomian &w1, Wielomian &w2) {

8

Wielomian wynik = w1;

9

for (int i=0; i<=w2.st; i++)

10

wynik.wsp[i] += w2.wsp[i];

11

return wynik;

12

}

Najlepiej trzymać się z dala od przyjaciół!

background image

Programowanie Obiektowe

24

l-wartości i r-wartości

wszystkie zmienne i wartości stałe leżą w pamięci, ale nie zawsze są w
pełni adresowalne

l-wartość – ang. lvalue, location value

to wartość, która jest odwołaniem do konkretnego miejsca w pamięci

w zamyśle ”wartość, która może stać po lewej stronie instrukcji
przypisania”

wyjątek: stała to też l-wartość, ale nie może stać po lewej stronie

r-wartość – ang. rvalue, read value

to dowolna wartość wyrażenia – mamy dostęp do wartości, ale
niekoniecznie do adresu pod którym leży

przykłady: stałe użyte w wyrażeniach, tymczasowe zmienne
przechowujące wyniki wyrażeń

wartość, która może stać po prawej stronie instrukcji przypisania

background image

Programowanie Obiektowe

25

l-wartości i r-wartości — c.d.

niepoprawne wyrażenia:

1

1 = 5+3;

2

sqrt(x) = 17;

3

int &x = 2;

// potrzebna l

warto´s´c z prawej strony

niepoprawne wywołania funkcji

1

void f (int &x)

2

{

3

x = 2

2;

4

}

5

main()

6

{

7

f(3+4);

// nie mo˙zna, bo 3+4 daje warto´s´c tymczasow ˛

a

8

}

background image

Programowanie Obiektowe

26

niepoprawne wywołania metod

1

class Wielomian

2

{

3

...

4

friend Wielomian Dodaj(Wielomian &, Wielomian &);

5

};

6

7

main()

8

{

9

Wielomian w1, w2, w3;

10

w3 = Dodaj(w1,w2);

// bł ˛

ad! Dodaj() wymaga l

warto´sci

11

Dodaj(w1, Dodaj(w2, w3));

// te˙z bł ˛

ad wynik Dodaj() to nie l

warto´s´c

12

}

background image

Programowanie Obiektowe

27

Obiekty tymczasowe i referencje do stałych (const &)

powstają przy wyliczaniu wartości wyrażeń (wyniki częściowe), zwracaniu
wartości funkcji itp.

żyją do czasu wyliczenia pełnego wyrażenia w którym występują

mogą inicjalizować stałe referencyjne lub deklarowane obiekty, wtedy żyją
tak długo jak to co zainicjowały

1

const int &x = 5;

2

const int &n = 4+3;

3

const Wielomian &w = Dodaj(w1, w2);

// ok

background image

Programowanie Obiektowe

28

Obiekty tymczasowe – przykład Stroustrupa

1

string s1, s2, s3;

2

const char

cs= (s1+s2).c_str() ;

3

cout << cs;

// mo˙ze si ˛e uda...

4

if (strlen(cs=(s2+s3).c_str())<8 && cs[0]==´a´) {

5

// chcesz u˙zy´c cs? powodzenia...

6

}

Tak czy inaczej to bardzo brzydki styl programowania.

background image

Programowanie Obiektowe

29

Polimorfizm – przeciążanie operatorów

pomysł nie całkiem nowy:

1

5 + 17

5 . 0 + 1 7 . 0

2

5 / 17

5 . 0 / 17

operatory, które można przeciążać

1

+

/

%

^

&

|

~

!

2

=

<

>

+=

=

=

/ =

%=

^=

&=

3

| =

<<

>>

>>= <<= ==

! =

<=

>=

&&

4

| |

++

−− −

>

,

>

[ ]

( )

new d e l e t e

nie można tworzyć własnych operatorów

nie można definiować operatorów o ww nazwach ale z inną liczbą
argumentów niż oryginalnie

background image

Programowanie Obiektowe

30

Przeciążanie operatorów – deklaracje

Operatory, których pierwszym argumentem jest obiekt pewnej klasy mogą być
zadeklarowane jako niezależne lub wewnątrz tej klasy:

niezależnie (na zewnątrz klasy) – często warto by taki operator był
zaprzyjaźniony z klasą:

1

class Wielomian

2

{

3

...

4

friend Wielomian operator+(const Wielomian &, const Wielomian &);

5

};

6

7

Wielomian operator+(const Wielomian &w1, const Wielomian &w2)

8

{

9

...

10

}

background image

Programowanie Obiektowe

31

wewnątrz klasy (pierwszy argument operatora ukryty – to obiekt
wywołujący):

1

class Wielomian

2

{

3

...

4

Wielomian operator+(const Wielomian &);

5

};

6

7

Wielomian Wielomian::operator+(const Wielomian &w)

8

{

9

...

10

stopien = max(st, w.st);

11

}

przykłady deklaracji operatorów:

1

double operator[](int index);

2

Wielomian &operator=(const Wielomian &);

3

int operator==(const Wielomian &, const Wielomian &);

background image

Programowanie Obiektowe

32

Przeciążanie operatorów – dwie szkoły

Szkoła 1:

jeśli tylko się da (pierwszy argument tego typu) to wewnątrz klasy, np:

1

Wielomian &operator+=(const Wielomian &);

2

Wielomian operator+(const Wielomian &);

3

int operator==(const Wielomian &);

Szkoła 2:

wewnątrz klasy te, które są w szczególny sposób związane z jednym
obiektem definiowanej klasy, np:

1

Wielomian &operator+=(const Wielomian &);

jeśli operator w sposób równorzędny dotyczy dwóch obiektów tego
typu, to sprawiedliwie jest umieścić go poza klasą, np:

1

Wielomian operator+(const Wielomian &, const Wielomian &);

2

int operator==(const Wielomian &, const Wielomian &);

background image

Programowanie Obiektowe

33

Przeciążanie operatorów – c.d.

Uwaga na referencje!

Najlepiej by definiowany operator był logicznie maksymalnie bliski
oryginalnego znaczenia

Operator indeksowania – przede wszystkim dla tablic

1

int IntArray::operator[](int index);

Operator wywołania funkcji – klasy w roli funkcji

1

JakisTyp Klasa::operator()(

/

argumenty

/

);

Operator wskazywania – niby obiekt, a jak wskaźnik

1

InnaKlasa

Klasa::operator

>();

background image

Programowanie Obiektowe

34

Operator przypisania – szczególne znaczenie gdy pamięć przydzielana jest
dynamicznie

1

class Wektor

2

{

3

int wymiar;

4

double

wsk;

5

public:

6

Wektor(int _wymiar);

7

Wektor(const Wektor &w);

8

~Wektor();

9

Wektor &operator=(const Wektor &w);

10

double &operator[](int index);

11

};

background image

Programowanie Obiektowe

35

1

Wektor::~Wektor()

2

{

3

delete[] wsk;

4

}

5

Wektor &Wektor::operator=(const Wektor &w)

6

{

7

wymiar = w.wymiar;

8

delete[] wsk;

9

wsk = new double[wymiar];

10

memcpy(wsk, w.wsk, wymiar

sizeof(

wsk));

11

}

12

Wektor::Wektor(const Wektor &w)

13

{

14

wsk = 0;

15

this = w;

16

}

background image

Programowanie Obiektowe

36

Operatory konwersji typów, np:

1

operator int();

2

operator double();

3

operator char

();

Przyklad:

1

class MyString

2

{

3

char

str;

4

public:

5

MyString(char

s);

6

operator char

() {return str;}

7

};

8

main() {

9

char str[20];

10

MyString s(

"Ala"

);

11

strcpy(str, s);

12

}

background image

Programowanie Obiektowe

37

Operatory

++

i

−−

1

Typ operator++();

// przedrostkowy

2

Typ operator++(int);

// przyrostkowy

Należy unikać zbyt skomplikowanych wyrażeń, w tym takich, które stosują
operatory

++

bądź

−−

do zmiennych, występujących w wyrażeniu więcej

niż raz.
Przykład nieintuicyjnego działania kompilatora:

1

int id(int x) {return x;}

2

main() {

3

int z = 2;

4

cout << z + z++ << endl;

5

z = 2;

6

cout << z + id(z++) << endl;

7

z = 2;

8

cout << id(z++) + z << endl;

9

}

generuje wyjście

1

4

2

5

3

5

background image

Programowanie Obiektowe

38

Operatory dla wielomianów

1

class Wielomian

2

{

3

...

4

public :

5

Wielomian &operator=(const Wielomian &);

6

Wielomian &operator

=(double c);

7

Wielomian &operator

=(const Wielomian &);

8

};

9

Wielomian operator

(const Wielomian &, double c);

10

Wielomian operator

(const Wielomian &, const Wielomian &);

background image

Programowanie Obiektowe

39

1

Wielomian &Wielomian::operator=(const Wielomian &w)

2

{

3

st = w.st;

4

/

mo˙zna tak

5

for (int i=0; i<st+1; i++)

6

wsp[i] = w.wsp[i];

7

/

8

// ale jest lepsze rozwi ˛

azanie:

9

for (double

w1=wsp+st+1,

w2=w.wsp+st+1; w1

−−

>wsp;)

10

w1 =

∗−−

w2;

11

return

this;

12

}

background image

Programowanie Obiektowe

40

1

Wielomian &Wielomian::operator

=(double c)

2

{

3

for (double

w=wsp+st+1; w

−−

>wsp;)

4

w

= c;

5

return

this;

6

}

7

8

Wielomian Wielomian::operator

(const Wielomian &w, double c)

9

{

10

Wielomian ww(w);

11

/

Tak nie, bo 1. nie ma sensu powiela´c, 2. potrzeba by zaprzyja´znienia

12

for (int i=0; i<st+1; i++)

13

ww.wsp[i]

= c;

/

14

ww

= c;

// Tak łatwiej i mniej miejsca na bł ˛edy

15

return w;

16

}

background image

Programowanie Obiektowe

41

Strumienie, operatory << i >>

Dociążanie operatorów wewnątrz własnych klas:

1

class Cos

2

{

3

public:

4

ostream &operator <<(ostream &o)

5

{return o <<

"co´s"

;}

6

};

Lepiej nie, bo wychodzą dziwactwa:

1

main()

2

{

3

Cos z;

4

cout << z;

// bł ˛

ad kompilacji

5

z << cout;

// OK, ale chyba nie o to chodziło

6

z << cout <<

" i co´s jeszcze"

;

// a fuj!

7

}

background image

Programowanie Obiektowe

42

Dociążanie operatorów na zewnątrz własnych klas:

1

ostream &operator <<(ostream &o, Cos &obiekt)

2

{

3

return o <<

"co´s"

;

4

}

Teraz pełny porządek:

1

main()

2

{

3

Cos z;

4

z << cout;

// bł ˛

ad kompilacji

i bardzo dobrze

5

cout << z;

// OK

6

cout << z <<

" i co´s jeszcze"

;

// OK

7

}

background image

Programowanie Obiektowe

43

Dociążanie operatorów strumieniowych – uwaga na styl!

Zwracamy

istream&

lub

ostream&

, bo inaczej:

1

void operator <<(ostream &o, Cos &obiekt)

2

{

3

o <<

"co´s"

;

4

}

5

main()

6

{

7

Cos z;

8

cout << z <<

" i co´s jeszcze"

;

// bł ˛

ad kompilacji

9

}

background image

Programowanie Obiektowe

44

Operatory bez rozrzutności – const & raz jeszcze

1

class Zespolona

2

{

3

public:

4

double re;

5

double im

6

Zespolona(double r, double i);

7

Zespolona(const Zespolona &z);

8

Zespolona operator=(const Zespolona &z);

9

};

10

Zespolona operator+(const Zespolona &z1, const Zespolona &z2) { ... }

11

void main() {

12

Zespolona z1(0,0), z2(1,1), z3(2,2);

13

z3 = z1+z2+z3;

14

}

Konstruktor kopiujący wołany raz – bez const & w operatorze + aż 4 razy!

background image

Programowanie Obiektowe

45

static

w języku C

zmienna globalna ograniczona do modułu

1

static int x;

widoczna tylko w ramach jednego pliku

różne pliki mogą deklarować zmienne statyczne o tej samej nazwie nie
powodując konfliktów przy scalaniu programu

zmienna w funkcji

1

void funkcja(void) {

2

static int licznik = 0;

3

licznik++;

4

...

5

}

pamięć przydzielona i inicjowana przy pierwszym wywołaniu i
zwalniana na zakończenie programu

zawartość „żyje” pomiędzy kolejnymi wywołaniami funkcji

background image

Programowanie Obiektowe

46

static

w C++ – pola statyczne

pola statyczne (static class members) to pola dzielone przez wszystkie
obiekty danej klasy

1

class Wielomian

2

{

3

static int ileObiektow;

4

public:

5

Wielomian() {ileObiektow++;}

6

};

7

int Wielomian::ileObiektow = 0;

jeden dla wszystkich, co oznacza, że modyfikacja pola w dowolnym
obiekcie zmienia to pole we wszystkich pozostałych

publiczne pole statyczne jest niemal równoważne zmiennej globalnej
dostępnej przez

Klasa::pole

oprócz deklaracji w klasie niezbędna jest deklaracja na zewnątrz
(ewentualnie z inicjalizacją)

background image

Programowanie Obiektowe

47

Przykład klasy wektorów bitowych

1

class WektorBitowy

2

{

3

unsigned int

bity;

4

int rozmiar;

5

6

public :

7

WektorBitowy(int rozmiar);

8

~WektorBitowy();

9

10

WektorBitowy &operator+=(int nrBitu);

// Wł ˛

acz bit

11

WektorBitowy &operator

=(int nrBitu);

// Wył ˛

acz bit

12

int operator[](int nrBitu);

// Czy bit jest wł ˛

aczony

13

14

WektorBitowy &operator|=(const WektorBitowy &);

15

WektorBitowy &operator&=(const WektorBitowy &);

background image

Programowanie Obiektowe

48

16

...

17

friend WektorBitowy operator|(const WektorBitowy &,

18

const WektorBitowy &);

19

...

20

};

21

22

WektorBitowy::WektorBitowy(int rozmiar)

23

{

24

WektorBitowy::rozmiar = rozmiar/(sizeof(int)

8)+1;

25

bity = new int[WektorBitowy::rozmiar];

26

}

27

28

WektorBitowy::~WektorBitowy()

29

{

30

delete[] bity;

31

}

background image

Programowanie Obiektowe

49

Początek projektowania obiektowego

Przykład: Model silnika samochodu wraz z niezbędnymi okolicami

Obiekty – części stanowiące odrębną całość z pewną wyraźnie określoną
funkcjonalnością:

akumulator

stacyjka

rozrusznik

silnik

koło zamachowe

wał korbowy

popychacze, zawory, cylindry, . . .

alternator

. . .

background image

Programowanie Obiektowe

50

Początek projektowania obiektowego – c.d.

Zadania klas

Wyodrębnienie osobnych elementów funkcjonalnych

Zamknięcie w jedną całość wartości opisujących obiekt i metod
funkcjonowania obiektu

Przykład: stacyjka

pozycja kluczyka

funkcja zmiany położenia kluczyka –

stacyjka.przeł ˛

acz()

:

przekaż prąd układowi zapłonu –

układZapłonu.zasil()

przekaż prąd rozrusznikowi –

rozrusznik.zasil()

Możliwość wielokrotnego użycia klasy – wiele podobnych obiektów

Przykład: cylindry, korbowody, tłoki, zawory, świece zapłonowe,
przekaźniki

Ułatwienie projektowania aplikacji – dziel i zwyciężaj – wyodrębniaj
klasy/obiekty i implementuj zredukowany zakres funkcji

background image

Programowanie Obiektowe

51

Dziedziczenie, klasy pochodne

1

class IntArray

2

{

3

int dim;

4

int

values;

5

public :

6

IntArray() : dim(0), values(0) {}

7

IntArray(int Dim) : dim(Dim) {values = new int[dim];}

8

// ...

9

int operator[](int index) {return values[index];}

10

};

11

class IntSortArray : public IntArray

12

{

13

public :

14

IntSortArray(int Dim) : IntArray(dim) {}

15

};

background image

Programowanie Obiektowe

52

Dziedziczenie – kontrola dostępu

dziedziczenie

w klasie bazowej

public

protected

private

public

public

protected

protected

protected

protected

private

private

private

background image

Programowanie Obiektowe

53

Hierarchie klas

Czasowy

Pracownik

Sekretarz

Kierownik

CzasowySekretarz

Konsultant

Dyrektor

1

class Czasowy {

/

...

/

};

2

class Pracownik {

/

...

/

};

3

class Sekretarz : public Pracownik {

/

...

/

};

4

class Kierownik : public Pracownik {

/

...

/

};

5

class CzasowySekretarz

6

: public Czasowy, public Sekretarz {

/

...

/

};

7

class Konsultant

8

: public Czasowy, public Kierownik {

/

...

/

};

background image

Programowanie Obiektowe

54

Wielokrotne dziedziczenie

Osoba

Osoba

Czasowy

Pracownik

Sekretarz

Kierownik

CzasowySekretarz

Rozstrzyganie niejednoznaczności

1

// Osoba posiada metod ˛e Nazwisko()

2

// Czasowy i Pracownik posiadaj ˛

a metody Wynagrodzenie()

3

CzasowySekretarz p;

4

p.Wynagrodzenie();

// Bł ˛

ad

5

p.Czasowy::Wynagrodzenie();

// OK

6

p.Pracownik::Wynagrodzenie();

// OK

7

p.Osoba::Nazwisko();

// Bł ˛

ad

background image

Programowanie Obiektowe

55

Wirtualne klasy bazowe

Osoba

Czasowy

Pracownik

Sekretarz

Kierownik

CzasowySekretarz

1

class Czasowy : public virtual Osoba {

/

...

/

};

2

class Pracownik : public virtual Osoba {

/

...

/

};

3

class Sekretarz : public Pracownik {

/

...

/

};

4

class CzasowySekretarz

5

: public Czasowy, public Sekretarz {

/

...

/

};

background image

Programowanie Obiektowe

56

Wirtualne klasy bazowe – c.d.

Jedna kopia obiektu klasy bazowej

Konstruktor wirtualnej klasy bazowej musi być wołany przez konstruktor
każdej klasy potomnej

1

CzasowySekretarz::CzasowySekretarz(???)

2

: Czasowy(???), Sekretarz(???),

3

Osoba(???)

4

{

5

...

6

}

Inaczej mielibyśmy niejednoznaczność, bo każda z klas

Czasowy

i

Sekretarz

może inaczej inicjować obiekt typu

Osoba

.

background image

Programowanie Obiektowe

57

Uwaga na transformacje typów wskaźników:

1

CzasowySekretarz

p;

2

Czasowy

pt = (Czasowy

)p;

3

Sekretarz

ps = (Sekretarz

)p;

4

Osoba

po = (Osoba

)p;

Założenie merytorycznej poprawności tych konwersji łatwo prowadzi do
sprzeczności – obiekty różnych typów pod tym samym adresem!

Rozwiązanie: wykorzystanie Runtime Type Identification (RTTI), ale o
tym później.

background image

Programowanie Obiektowe

58

Metody wirtualne

1

class Figura {

2

public :

3

virtual void Obroc(int);

4

virtual void Rysuj();

5

void Skaluj(float wsp);

6

...

7

};

8

class Okrag : public Figura {

9

int x, y;

10

int promien;

11

public :

12

void Obroc(int);

13

void Rysuj();

14

void Skaluj(float wsp);

15

};

background image

Programowanie Obiektowe

59

1

void main()

2

{

3

Okrag o;

4

Figura

f = &o;

5

f

>Skaluj(0.5);

// woła Figura::Skaluj()

6

f

>Rysuj();

// woła Okrag::Rysuj()

7

}

Uwagi:

Metody wirtualne wołane w konstruktorze są uruchamiane jak niewirtualne
(obiekt potomny jeszcze nie istnieje - a dokładniej nie został zainicjowany -
więc nie może działać)

Wirtualne metody zwiększają rozmiary klas (odpowiednie adresy do funkcji
muszą być przechowywane razem z obiektem)

background image

Programowanie Obiektowe

60

Bardziej realna postać problemu:

1

void SkalujIRysuj(Figura

f)

2

{

3

f

>Skaluj();

4

f

>Rysuj();

5

}

6

void main()

7

{

8

Okrag o;

9

...

10

SkalujIRysuj(&o);

11

}

background image

Programowanie Obiektowe

61

Wirtualne destruktory

1

class Figura {

2

public :

3

...

4

virtual ~Figura() {}

5

};

6

class ListaFigur {

7

Figura

figura[1000];

8

int ileFigur;

9

public:

10

...

11

~ListaFigur();

// zwalnia pami ˛e´c po wszystkich figurach

12

void Dodaj(Figura

);

13

void Rysuj();

14

};

background image

Programowanie Obiektowe

62

1

ListaFigur::~ListaFigur() {

2

for (int i=0; i<ileFigur; i++)

3

delete figura[i];

4

}

5

void ListaFigur::Rysuj() {

6

for (int i=0; i<ileFigur; i++)

7

figura[i]

>Rysuj();

8

}

9

10

void DwieFigury()

11

{

12

ListaFigur l;

13

l.Dodaj(new Okrag(30, 20, 15));

14

l.Dodaj(new Kwadrat(5, 5, 25));

15

l.Rysuj();

16

}

background image

Programowanie Obiektowe

63

Kolejność wywołań konstruktorów i destruktorów

konstruktory od klasy pierwotnej do „najbardziej potomnej”

destruktory w odwrotnej kolejności

w dziedziczeniu wielokrotnym konstruktory są wołane w porządku
odpowiadającym deklaracji dziedziczenia

konstruktory obiektów będących polami klasy są wołane po konstruktorze
klasy, w której występują, w kolejności, w jakiej pojawiają się w deklaracji
klasy

inicjalizacja pól może być umieszczona w sposób analogiczny do wywołań
konstruktorów klas bazowych (musi w sytuacji, kiedy klasa pola-obiektu ma
tylko konstruktory z niepomijalnymi argumentami)

z destruktorami mamy sytuację analogiczną

wirtualne klasy bazowe są zawsze inicjowane przed niewirtualnymi

background image

Programowanie Obiektowe

64

„Czyste” klasy wirtualne (abstrakcyjne)

1

class Figura {

2

public :

3

virtual void Obroc(int) = 0;

4

virtual void Rysuj() = 0;

5

};

6

void main() {

7

Figura f;

// Bł ˛

ad

8

}

Nie da się stworzyć obiektu typu abstrakcyjnego

Mechanizm interfejsów (Pascal/Delphi, technologie MS Windows: ActiveX
itp.)

background image

Programowanie Obiektowe

65

Wzorce (ang. templates)

Przykład zapotrzebowania - minimum

wiele funkcji – nieprzyjemne...

1

int min(int arg1, int arg2) {

2

return arg1 < arg2? arg1 : arg2;

3

}

4

double min(double arg1, double arg2) {

5

return arg1 < arg2? arg1 : arg2;

6

}

#define

– niebezpieczeństwo wielokrotnego liczenia

1

#define MIN(a,b) (((a)<(b)) ? (a) : (b))

2

...

3

z = MIN(x.LiczDuzo(),1000);

4

// rozwini ˛ete zostanie do:

5

z = (((x.LiczDuzo())<(1000)) ? (x.LiczDuzo()) : (1000));

background image

Programowanie Obiektowe

66

Wzorce funkcji

1

template <class T>

2

T Min(T arg1, T arg2)

3

{

4

return arg1 < arg2? arg1 : arg2;

5

}

6

void main()

7

{

8

int i=5, j=10;

9

double x=1.9, y=3;

10

cout << Min(i,j) << endl;

// 5 T == int

11

cout << Min(x,y) << endl;

// 1.9 T == double

12

cout << Min<int>(x+y,x

y) << endl;

//

1

13

}

background image

Programowanie Obiektowe

67

Wzorce klas

1

template <class TypObiektu> class Stos

2

{

3

int rozmiar;

4

TypObiektu

pocz,

wierz;

5

public:

6

Stos(int r) {pocz = wierz = new TypObiektu[rozmiar = r];}

7

~Stos() {delete[] pocz;}

8

9

void Odloz(TypObiektu o) {

wierz++ = o;}

10

TypObiektu Pobierz() {return

∗−−

wierz;}

11

};

background image

Programowanie Obiektowe

68

Wzorce – użycie klasy Stos

1

void main()

2

{

3

int i;

4

Stos<int> stos(100);

5

for (i=0; i<20; i++)

6

stos.Odloz(i

i);

7

for (i=0; i<20; i++)

8

cout << stos.Pobierz() <<

"\n"

;

9

}

background image

Programowanie Obiektowe

69

Wzorce – wektor dowolnego typu

1

template <class T, int d>

2

class Array

3

{

4

protected :

5

int dim;

6

T

values;

7

public :

8

Array() {values = new T[dim=d];}

9

~Array() {delete[] values;}

10

T &operator[](int index);

11

};

Lepiej definiować wymiar w konstruktorze – tak jak było dla stosu

background image

Programowanie Obiektowe

70

Wzorce – definicja metody

1

template <class T, int d>

2

T &Array<T, d>::operator[](int index)

3

{

4

if (index <0 || index >=dim)

5

exit(1);

6

return values[index];

7

}

background image

Programowanie Obiektowe

71

Wzorce – dziedziczenie

1

typedef int CompareFun(const void

arg1, const void

arg2);

2

3

template <class T, int d>

4

class SortArray : public Array<T, d>

5

{

6

public :

7

void QuickSort(CompareFun

f);

8

};

9

10

template <int d>

11

class IntArray : public Array<int, d>

12

{

13

public :

14

...

15

};

background image

Programowanie Obiektowe

72

Wyjątki (exceptions)

Zgłaszanie wyjątków

1

throw 123;

2

throw

"Nie wiem co si ˛e stało"

;

3

throw ExceptionTypeObject;

4

throw WyjatekZOpisem(

"Przekroczenie zakresu!"

);

Deklaracje klas dla wyjątków

1

class TypWyj ˛

atku {};

2

struct WyjatekZOpisem

3

{

4

string opis;

5

WyjatekZOpisem(char

o) {opis = o;}

6

};

background image

Programowanie Obiektowe

73

Przechwytywanie wyjątków

1

try

2

{

3

lista instrukcji

4

}

5

catch (ExceptionType o)

6

{

7

lista instrukcji

8

}

9

catch (...)

10

{

11

lista instrukcji

12

}

background image

Programowanie Obiektowe

74

Przechwytywanie wyjątków – więcej informacji

1

try

2

{

3

DuzoLiczenia();

4

}

5

catch (ExceptionType o)

6

{

7

Komunikat(o.opis);

8

}

9

catch (...)

10

{

11

Komunikat(

"Nieznany bł ˛

ad w funkcji DuzoLiczenia()"

);

12

}

background image

Programowanie Obiektowe

75

Przechwytywanie wyjątków – niebezpieczeństwo wycieków pamięci

1

try

2

{

3

Zadanie

z = new Zadanie();

4

z

>PoliczWszystko();

5

delete z;

6

}

7

catch (...)

8

{

9

Komunikat(

"Co´s si ˛e stało i z nie zwolniony :

("

);

10

}

background image

Programowanie Obiektowe

76

Przechwytywanie wyjątków – sprzątamy niezależnie czy wystąpił wyjątek
czy nie

1

Zadanie

z=0;

// to zerowanie jest wa˙zne

2

try

3

{

4

z = new Zadanie();

5

z

>PoliczWszystko();

6

}

7

__finally

8

{

9

delete z;

10

Komunikat(

"I posprz ˛

atane :

)"

);

11

}

background image

Programowanie Obiektowe

77

Wyjątki (exceptions)

Typy wyjątków wewnątrz klas

1

class NazwaKlasy

2

{

3

...

4

class TypWyj ˛

atku {};

5

}

Wówczas przechwytywanie wyjątków wygląda tak:

1

catch (NazwaKlasy::TypWyj ˛

atku x)

2

{

3

...

4

}

background image

Programowanie Obiektowe

78

Wyjątki – prosty przykład

1

#include <stdio.h>

2

3

class ArgumentSilni{};

4

5

long Silnia(int x)

6

{

7

if (x < 0) throw ArgumentSilni();

8

return (x <= 1)? 1 : x

Silnia(x

1);

9

}

10

11

main()

12

{

13

int arg;

14

try

15

{

background image

Programowanie Obiektowe

79

16

while (1)

17

{

18

printf(

"Podaj argument : "

);

19

scanf(

"%d"

, &arg);

20

printf(

"%d! = %ld\n"

, arg, Silnia(arg));

21

}

22

}

23

catch (ArgumentSilni x)

24

{

25

printf(

"Niepoprawny argument dla funkcji Silnia().\n"

);

26

return 1;

27

}

28

catch (...)

29

{

30

printf(

"Nie obsługiwany wyj ˛

atek.\n"

);

31

return 2;

32

}

33

}

background image

Programowanie Obiektowe

80

Operator ::

funkcje przykrywające zmienne

1

int x;

2

int funkcja(float x) {

3

x = 4;

// typ float i lokalna zmienna x

4

...

5

return 0;

6

}

zmienna globalna jest dostępna przed deklaracją ją przykrywającą

1

int x;

2

int funkcja() {

3

x = 5;

// zmienna globalna

typ int

4

...

5

float x;

6

x = 4;

// zmienna lokalna

typ float

7

}

background image

Programowanie Obiektowe

81

Operator :: daje dostęp do przykrytej zmiennej globalnej

1

int x = 5;

2

int funkcja()

3

{

4

float x;

5

...

6

x = ::x;

7

...

8

}

background image

Programowanie Obiektowe

82

Przestrzenie nazw – namespaces

Przykład:

1

namespace A {

2

void cokolwiek() {cout <<

"jeste´smy w przestrzeni A"

;}

3

}

4

namespace B {

5

void cokolwiek() {cout <<

"jeste´smy w przestrzeni B"

;}

6

}

7

main() {

8

cokolwiek();

// Bł ˛

ad! Funkcja niezdefiniowana.

9

A::cokolwiek();

// OK

10

B::cokolwiek();

// OK

11

}

background image

Programowanie Obiektowe

83

otwieranie bezpośredniego dostępu do przestrzeni nazw:

1

using namespace A;

Po otwarciu przestrzeni

A

:

1

main() {

2

cokolwiek();

// OK

funkcja przestrzeni A

3

A::cokolwiek();

// OK

4

B::cokolwiek();

// OK

5

}

background image

Programowanie Obiektowe

84

otwieranie wszystkich możliwych przestrzeni jest równie uciążliwe jak nie
otwieranie żadnej:

1

using namespace A;

2

using namespace B;

3

main() {

4

cokolwiek();

// Bł ˛

ad! Dwuznaczno´s´c.

5

A::cokolwiek();

// OK

6

B::cokolwiek();

// OK

7

}

funkcje definiowane bez jawnej deklaracji przestrzeni to funkcje w
podstawowej przestrzeni nazw (o pustej nazwie – dostęp przez

::id

)

definiując bibliotekę należy utworzyć dla niej własną przestrzeń nazw

background image

Programowanie Obiektowe

85

Metody typu

inline

1

template<class T> class Vector

2

{

3

T

data;

4

int size;

5

public:

6

Vector(int s) {data=new T[size=s];}

7

~Vector() {delete[] data;}

8

inline T &operator[] (int i);

9

int Size() {return size;}

10

};

11

12

template<class T> T &operator[] (int i)

13

{

14

return data[i];

15

}

Uwaga na opcje kompilatora blokujące wywołania

inline

!

background image

Programowanie Obiektowe

86

Wskaźniki do funkcji

1

#include <stdio.h>

// dla printf()

2

#include <stdlib.h>

// dla qsort()

3

#include <string.h>

// dla strcmp() i stricmp()

4

5

typedef int (

Funkcja)(char

∗∗

, char

∗∗

);

6

7

int Porownaj1(char

∗∗

s1, char

∗∗

s2) {

8

return strcmp(

s1,

s2);

9

}

10

int Porownaj2(char

∗∗

s1, char

∗∗

s2) {

11

return stricmp(

s1,

s2);

12

}

13

int Porownaj3(char

∗∗

s1, char

∗∗

s2) {

14

if (strlen(

s1) > strlen(

s2)) return 1;

15

if (strlen(

s1) < strlen(

s2)) return

1;

16

return 0;

17

}

background image

Programowanie Obiektowe

87

18

19

void main()

20

{

21

int i, j;

22

char

ala[] = {

"ALA MA KOTA"

,

"Ala ma Kota"

,

"alamakota"

,

"Ala"

};

23

Funkcja f[] = {Porownaj1, Porownaj2, Porownaj3};

24

for (i=0; i<sizeof(f)/sizeof(

f); i++)

25

printf(

"Wynik[%d] = %d\n"

, i, f[i](ala, ala+1));

26

for (i=0; i<sizeof(f)/sizeof(

f); i++)

27

{

28

qsort(ala, sizeof(ala)/sizeof(

ala), sizeof(

ala), f[i]);

29

printf(

"\nPo sortowaniu nr %d\n"

, i);

30

for (j=0; j<sizeof(ala)/sizeof(

ala); j++)

31

printf(

"%s\n"

, ala[j]);

32

}

33

}

background image

Programowanie Obiektowe

88

Wskaźniki do pól i metod, operatory

.*

i

->*

1

class A

2

{

3

public:

4

int z;

5

int fun(int x) {return x = 0;}

6

};

7

8

typedef int A::

Aint;

9

typedef int (A::

FUN)(int);

10

11

int F(A x, int A::

ai) {

12

return x.

ai;

13

}

14

int Fp(A

x, Aint ai) {

15

return x

>

ai;

background image

Programowanie Obiektowe

89

16

}

17

int G(A x, FUN f) {

18

return (x.

f)(12);

19

}

20

int Gp(A

x, FUN f) {

21

return (x

>

f)(12);

22

}

23

24

int main()

25

{

26

A a;

27

int A::

c = &A::z;

28

F(a, c);

29

Fp(&a, &A::z);

30

G(a, A::fun);

31

Gp(&a, A::fun);

32

return 0;

33

}

background image

Programowanie Obiektowe

90

Stałe a klasy –

const

1

const int x=5;

2

const int y;

// Bł ˛

ad! Stała niezainicjowana

3

const Macierz Id5(5);

4

const int v[] = {1, 2, 3, 4};

// ka˙zde v[i] jest stałe

5

6

main()

7

{

8

Id5.Rzad();

// OK

9

Id5.Triangularyzacja();

// Bł ˛

ad! Metoda zmienia obiekt

10

}

Dodanie

const

to stworzenie nowego typu

1

const char

pc;

// wska´znik na stały znak

2

char

const cp;

// stały wska´znik na znak

3

char const

pc2;

// wska´znik na stały znak

background image

Programowanie Obiektowe

91

const

w deklaracjach argumentów funkcji

1

char

strcpy(char

p, const char

q);

// nie mo˙zna zmieni´c

q

Deklaracje metod wywoływalnych również dla stałych:

1

class Macierz

2

{

3

int ileKolumn;

4

public:

5

int Rzad() const;

6

int IleKolumn() const {return ileKolumn;}

7

...

8

};

background image

Programowanie Obiektowe

92

Pola zmienne (

mutable

)

Czasami istnieje potrzeba modyfikacji pewnych pól „organizacyjnych” w
obiektach deklarowanych jako stałe

właściwa reprezentacja obiektu nie zmienia się, ale mogą zmieniać się
pewne dane związane z obsługą

np. Obiekt daty i obsługa cache’u z datą jako napisem:

1

class Date {

2

mutable bool cache_valid;

3

mutable char cache[20];

4

void compute_cache_value() const;

// fill cache

5

public:

6

char

string_rep() const;

// string representation

7

// ...

8

};

background image

Programowanie Obiektowe

93

1

char

Date::string_rep() const

2

{

3

if (cache_valid == false) {

4

compute_cache_value();

5

cache_valid = true;

6

}

7

return cache;

8

}

Uwaga! Funkcje deklarowane dla obiektów stałych mogą zmieniać pola
statyczne.

background image

Programowanie Obiektowe

94

Można też brutalnie:

1

class Date {

2

bool cache_valid;

3

char cache[20];

4

void compute_cache_value();

// fill cache

5

public:

6

char

string_rep() const;

// string representation

7

...

8

};

9

char

Date::string_rep() const

10

{

11

if (cache_valid == false) {

12

Date

th = (Date

)this;

13

th

>compute_cache_value();

14

th

>cache_valid = true;

15

}

16

return cache;

17

}

background image

Programowanie Obiektowe

95

Obiekty ulotne (

volatile

)

Deklaracja zmiennej jako

volatile

informuje kompilator, że wartość

zmiennej może się zmieniać w tle (w innym wątku)

Zakaz pewnych uproszczeń (optymalizacji) dla takich zmiennych

Kompilator nie może przechowywać zmiennej tylko w rejestrze.

Przykład:

1

volatile int ticks;

2

void timer( ) { ticks++; }

3

void wait (int interval) {

4

ticks = 0;

5

while (ticks < interval);

// Nie rób nic

6

}

Optymalizator mógłby zignorować polecenie wielokrotnego sprawdzania
warunku, bo nic się nie zmienia.

Uwaga: W C++ ulotne mogą być również metody klas – w ulotnym
obiekcie można używać tylko ulotnych metod.

background image

Programowanie Obiektowe

96

Zakresy życia obiektów

obiekty globalne – zaczynają przed

main()

, kończą po

main()

pola statyczne klas – jak obiekty globalne

pola niestatyczne – jak obiekt, w którym występują tj. od konstruktora do
destruktora

zmienne lokalne dla funkcji – od momentu deklaracji, do końca zakresu
(klamry kończącej blok)

parametry funkcji – zaczynają bezpośrednio przed wywołaniem funkcji,
kończą po zakończeniu działania funkcji

zmienne deklarowane w

for

– zakres pętli

zmienne tymczasowe (powstające podczas wyliczania wartości wyrażeń) –
od momentu konieczności przechowania wyniku cząstkowego do końca
wyznaczania wartości wyrażenia

background image

Programowanie Obiektowe

97

Różne drobne uwagi

elipsy (. . . ) a klasy

Uwaga: Argument przekazany funkcji o zmiennej liczbie argumentów nie
może być obiektem klasy, która definiuje konstruktor albo operator = (ale
oczywiście może być wskaźnikiem do takiej klasy)

Członkowie unii nie mogą implementować konstruktorów ani destruktorów

Konstruktory obiektów globalnych wołane są przed wywołaniem funkcji

main()

Jeśli klasa ma wirtualne funkcje, to zwykle powinna mieć też wirtualny
destruktor

Kolejność wyliczania podwyrażeń w wyrażeniu jest niezdefiniowana!

background image

Programowanie Obiektowe

98

RTTI

RunTime Type Identification pozwala:

(w trakcie działania programu) poznać typ danych, kiedy dysponujemy
tylko wskaźnikiem

na kontrolowaną konwersję wskaźnika klasy bazowej na wskaźnik klasy
potomnej – operator

dynamic_cast

sprawdzić, czy wskazywany obiekt jest pewnego znanego nam typu –
operator

typeid

background image

Programowanie Obiektowe

99

Operator

typeid

1

typeid( expression )

2

typeid( type

name )

zwraca referencję na obiekt typu

const type_info

klasa

type_info

implementuje

operator==

operator!=

metodę

const char

name() const;

metodę

bool before(const type_info &) const;

jeśli argument jest wskaźnikiem, to wynikiem jest identyfikacja
dynamicznego typu obiektu (odpowiedniego obiektu potomnego)

działa ze standardowymi typami i klasami użytkownika

Jeśli argument jest wskaźnikiem zerowym, to zgłaszany jest wyjątek

Bad_typeid

background image

Programowanie Obiektowe

100

1

class A { };

2

class B : A { };

3

void main() {

4

char C; float X;

5

6

if (typeid(C) == typeid(X)) cout <<

"Ten sam typ."

<< endl;

7

else cout <<

"Nie ten sam typ."

<< endl;

8

9

cout << typeid(int).name()

10

<<

" before "

<< typeid(double).name() <<

": "

11

<< typeid(int).before(typeid(double)) << endl;

12

13

cout <<

"double before int: "

14

<< typeid(double).before(typeid(int)) << endl;

15

16

cout << typeid(A).name()

17

<<

" before "

<< typeid(B).name() <<

": "

18

<< typeid(A).before(typeid(B)) << endl;

19

}

background image

Programowanie Obiektowe

101

Wyjście programu:

Nie ten sam typ.

int before double: 0

double before int: 1

A before B: 1

background image

Programowanie Obiektowe

102

Nowe metody konwersji typów

const_cast<Typ>(arg)

dynamic_cast<Typ>(arg)

reinterpret_cast<Typ>(arg)

static_cast<Typ>(arg)

Oczywiście, stare sposoby konwersji (te z C) również działają.

background image

Programowanie Obiektowe

103

const_cast<Typ>(arg)

dodaje lub zdejmuje modyfikator

const

lub

volatile

const_cast<Typ>(arg)

, typy

Typ

oraz

arg

muszą być takie same z

dokładnością do modyfikatorów

konwersja w czasie kompilacji

dowolna liczba modyfikatorów może być zniesiona bądź dodana jedną
konwersją

nie wymaga RTTI

Przykład:

1

void ZmienStala(const int &x)

2

{

3

int &z = const_cast<int &>(x);

4

z = 123;

5

}

Możliwe, ale bardzo nieładne...

background image

Programowanie Obiektowe

104

dynamic_cast<Typ>(arg)

Typ

– typ wskaźnikowy (w tym

void

) bądź referencyjny

arg

– wyrażenie dające w wyniku wskaźnik lub referencję (odpowiednio do

Typ

)

jeśli

Typ

to

void

, to wynikiem jest wskaźnik na obiekt najbardziej

potomnej klasy

konwersje z klasy potomnej do bazowej są wykonywane w czasie
kompilacji, w drugą stronę lub „na przełaj” hierarchii – w trakcie działania
programu

konwersja do klasy potomnej możliwa tylko dla klas polimorficznych

w przypadku powodzenia

dynamic_cast<Typ>(arg)

zwraca odpowiedni

wskaźnik,

w przypadku porażki:

zwraca 0 dla wskaźników

zgłasza wyjątek

Bad_cast

dla referencji

wymaga RTTI

background image

Programowanie Obiektowe

105

1

class Base1 {

2

virtual void f(void) {

/

klasa polimorficzna

/

}

3

};

4

class Base2 { };

5

class Derived : public Base1, public Base2 { };

6

7

int main(void) {

8

try {

9

Derived d,

pd;

10

Base1

b1 = &d;

11

12

// W dół hierarchii

z Base1 do derived

13

if ((pd = dynamic_cast<Derived

>(b1)) != 0)

14

{

15

cout <<

"Wynikowy wska´znik jest typu "

16

<< typeid(pd).name() << std::endl;

17

}

18

else

19

throw Bad_cast();

background image

Programowanie Obiektowe

106

20

21

// "Na przełaj"

z jednej bazowej do drugiej

22

Base2

b2;

23

if ((b2 = dynamic_cast<Base2

>(b1)) != 0) {

24

cout <<

"Wynikowy wska´znik jest typu "

25

<< typeid(b2).name() << endl;

26

}

27

else throw Bad_cast();

28

}

29

catch (Bad_cast) {

30

cout <<

"dynamic_cast nie powiodło si ˛e"

<< endl;

31

return 1;

32

}

33

catch (...) {

34

cout <<

"Nieznany wyj ˛

atek!"

<< endl;

35

return 1;

36

}

37

return 0;

38

}

background image

Programowanie Obiektowe

107

reinterpret_cast<Typ>(arg)

zmienia interpretację bitowej reprezentacji obiektu

Typ

– wskaźnik, referencja, typ arytmetyczny, wskaźnik do funkcji lub

wskaźnik do składowej

wskaźnik może być jawnie przekonwertowany do typu całkowitego

liczba całkowita może być konwertowana do wskaźnika

można konwertować na wskaźnik bądź referencję na nie zdefiniowany
jeszcze typ

poleca się używać w zamian za jawną konwersję np.

(int

)x

background image

Programowanie Obiektowe

108

1

void func(void

v) {

2

// Ze wska´znika do liczby całkowitej

3

int i = reinterpret_cast<int>(v);

4

...

5

}

6

7

void main() {

8

// Z liczby całkowitej do wska´znika

9

func(reinterpret_cast<void

>(5));

10

11

// ze wska´znika do funkcji na wska´znik

12

// do funkcji innego typu

13

typedef void (

PFV)();

14

15

PFV pfunc = reinterpret_cast<PFV>(func);

16

17

pfunc();

18

}

background image

Programowanie Obiektowe

109

static_cast<Typ>(arg)

Typ

– wskaźnik, referencja, typ arytmetyczny lub wyliczeniowy (

enum

)

zarówno

Typ

jak i

arg

muszą być w pełni znane w czasie kompilacji

jeśli konwersja może być wykonana środkami języka, to konwersja przez

static_cast

robi to samo

liczby całkowite mogą być konwertowane do typu wyliczeniowego, dla
wartości spoza zakresu zachowanie niezdefiniowane

wskaźnik na jeden typ może być konwertowany na wskaźnik na inny typ

wskaźnik do klasy

Y

może być konwertowany do wskaźnika do klasy

X

,

jeśli

Y

dziedziczy po

X

– konwersja możliwa jeśli:

istnieje jednoznaczny sposób konwersji z

Y

do

X

X

nie jest dziedziczona wirtualnie przez

Y

background image

Programowanie Obiektowe

110

static_cast<Typ>(arg)

– c.d.

obiekt może być przekonwertowany do

X&

, o ile wskaźnik do niego może

być przekonwertowany do

X

. Wynik jest l-wartością. Nie są wołane

żadne konstruktory ani operatory konwersji.

obiekt lub wartość można przekonwertować na obiekt pewnej klasy, jeśli
istnieje odpowiedni konstruktor bądź operator konwersji

wskaźnik do składowej może być przekonwertowany na inny wskaźnik do
składowej, jeśli oba wskazują składowe tej samej klasy, bądź różnych klas,
ale z jednoznacznym dziedziczeniem pomiędzy nimi

background image

Programowanie Obiektowe

111

Rozszerzenia Borland C++ Buildera

Typy

Typ

Przykład

Rozmiar

__int8

__int8 c = 127i8;

8 bitów

__int16

__int16 s = 32767i16;

16 bitów

__int32

__int32 i = 123456789i32;

32 bity

__int64

__int64 big = 12345654321i64;

64 bity

unsigned __int64

unsigned __int64 hugeInt =

64 bity

1234567887654321ui64;

Słowa kluczowe

__closure

__property

__published

__thread

i wiele innych, których opis można znaleźć w systemie pomocy Borland
C++ Buildera (C++ Builder Language Guide)

background image

Programowanie Obiektowe

112

__closure

Pozwala zadeklarować specjalny rodzaj wskaźnika do metody

Standard C++ pozwala jedynie na pełną specyfikację jak na stronie 89 i w
poniższym przykładzie:

1

class base

2

{

3

public:

4

int func(int x) { return x; }

5

};

6

typedef int (base::

pBaseMember)(int);

7

8

void main()

9

{

10

base baseObject;

11

pBaseMember m = base::func;

12

(baseObject.

m)(17);

13

}

background image

Programowanie Obiektowe

113

Standard C++ nie pozwala na to, by takiemu wskaźnikowi przypisać adres
do metody klasy potomnej:

1

class derived : public base

2

{

3

public:

4

int new_func(int x) { return 2

x; }

5

};

6

int main(int argc, char

argv[])

7

{

8

derived derivedObject;

9

pBaseMember m = derived::new_func;

// Bł ˛

ad! Ale:

10

pBaseMember m = (pBaseMember)(&derived::new_func);

// OK

11

}

background image

Programowanie Obiektowe

114

__closure

definiuje wskaźnik do metody związanej z konkretnym obiektem

Zależności hierarchii klas nie mają znaczenia – tylko liczba i typy
argumentów oraz typ zwracanej wartości.

Przykład nazwiązujący do poprzednich:

1

int main(int argc, char

argv[])

2

{

3

derived derivedObject;

4

int (__closure

derivedClosure)(int);

5

derivedClosure = derived::new_func;

// Bł ˛

ad!

6

derivedClosure = derivedObject.new_func;

// OK

7

derivedClosure(3);

// derivedObject.new_func(3);

8

return 0;

9

}

background image

Programowanie Obiektowe

115

__closure

działa również dla wskaźników:

1

void func1(base

pObj)

2

{

3

void (__closure

myClosure)(int);

4

myClosure = pObj

>func;

5

myClosure(1);

6

return;

7

}

8

9

int main(int argc, char

argv[])

10

{

11

derived derivedObject;

12

void (__closure

derivedClosure)(int);

13

derivedClosure = derivedObject.new_func;

14

derivedClosure(3);

15

func1(&derivedObject);

16

return 0;

17

}

background image

Programowanie Obiektowe

116

__closure

to podstawa Borlandowego środowiska RAD (Rapid

Application Development) – zarówno w Delphi jak i C++ Builderze –
pozwala przypisywać funkcje obsługi zdarzeń poszczególnym obiektom.

Przykłady:

zdarzenie

OnClick

dla obiektu klasy

TButton

zdarzenie

OnChange

dla obiektu klasy

TEdit

zdarzenie

OnMouseMove

dla obiektu dowolnej klasy dziedziczącej po

TControl

background image

Programowanie Obiektowe

117

__property

Zapotrzebowanie:

Często chronimy pola, ale tworzymy publiczne metody do ich obsługi. Na
przykład:

1

class XYZ {

2

int rozmiar;

3

char

bufor;

4

public:

5

...

6

int Rozmiar() {return rozmiar;}

7

void UstawRozmiar(int r) {rozmiar = r;

8

delete[] bufor; bufor = new char[rozmiar];}

9

};

Żmudne i trzeba pamiętać nazwy albo stosować zawsze ten sam schemat
(np.

GetXX()

i

SetXX()

).

background image

Programowanie Obiektowe

118

Ładniejsze rozwiązanie z użyciem

__property

1

class XYZ {

2

int _rozmiar;

3

char

bufor;

4

int Rozmiar() {return _rozmiar;}

5

void UstawRozmiar(int r) {_rozmiar = r;

6

delete[] bufor; bufor = new char[_rozmiar];}

7

public:

8

...

9

__property int rozmiar = {read = Rozmiar,

10

write = UstawRozmiar};

11

/

albo

/

12

__property int rozmiar = {read = _rozmiar,

13

write = UstawRozmiar};

14

};

Wówczas instrukcja

x.rozmiar = 5;

jest równoważna wywołaniu

x.UstawRozmiar(5);

.

background image

Programowanie Obiektowe

119

Syntaktyka

__property

:

1

__property type propertyName[index1Type index1]

2

[indexNType indexN] = { attributes };

gdzie

type

jest pewnym znanym typem (standardowym lub wcześniej

zdefiniowanym),

propertyName

jest identyfikatorem,

indexNType

jest pewnym znanym typem (standardowym lub wcześniej

zdefiniowanym),

indexN

jest nazwą parametru (indeksu) przekazywanego funkcjom

read

i

write

,

attributes

jest listą oddzielonych przecinkami deklaracji

read

,

write

,

stored

,

default

(lub

nodefault

) lub

index

.

Parametry

indexN

są opcjonalne – definiują własności tablicowe.

background image

Programowanie Obiektowe

120

Przykłady deklaracji

__property

:

1

class PropertyExample {

2

private:

3

int Fx,Fy;

4

float Fcells[100][100];

5

protected:

6

int readX() {return(Fx);}

7

void writeX(int newFx) {Fx = newFx;}

8

double computeZ() {

/

...

/

return(0.0);}

9

float cellValue(int row, int col)

10

{return(Fcells[row][col]);}

11

public:

12

__property int X = {read=readX, write=writeX};

13

__property int Y = {read=Fy};

14

__property double Z = {read=computeZ};

15

__property float Cells[int row][int col] =

16

{read=cellValue};

17

};

background image

Programowanie Obiektowe

121

Przykład wykorzystania

1

PropertyExample pe;

2

3

pe.X = 42;

// pe.writeX(42);

4

int myVal1 = pe.Y;

// myVal1 = pe.Fy;

5

double myVal2 = pe.Z;

// myVal2 = pe.ComputeZ();

6

float cellV = pe.Cells[3][7];

// cellV = pe.cellValue(3,7);

Własności mogą także:

przypisywać te same metody czytania i pisania do różnych własności
(z użyciem atrybutu

index

)

mieć wartości domyślne

być zapamiętywane w plikach opisu okien bądź nie

być rozszerzane w klasach potomnych

. . .

background image

Programowanie Obiektowe

122

__published

Wykorzystywane przez środowisko RAD Borlanda

Własności pojawiające się w tej sekcji są wyświetlane przez inspektora
obiektów (Object Inspector)

Tylko klasy dziedziczące po TObject mogą deklarować sekcję

__published

.

Dostępność składowych jest taka sama jak tych z sekcji

public

. Różnice są

jedynie w sposobie generowania informacji dla RTTI.

W sekcji

__published

nie można deklarować

konstruktorów, destruktorów,

pól tablicowych,

obiektów typów innych niż porządkowe, rzeczywiste, łańcuchowe,
zbiorowe, klasowe i wskazujące na składowe.

background image

Programowanie Obiektowe

123

__thread

Programowanie wielowątkowe – równolegle wykonywane wątki programu.

Zmienne globalne w programowaniu wielowątkowym

Zagrożenie problemami wielodostępu.

Prosty i atrakcyjny mechanizm komunikacji między wątkami

Czasami bardzo przydatne mogą być zmienne globalne w ramach wątku,
ale nie współdzielone przez różne wątki. Modyfikator

__thread

:

int __thread x;

deklaruje zmienną jako lokalną dla wątku, a zarazem globalną w ramach
wątku.

Modyfikator

__thread

może być użyty tylko dla zmiennych globalnych i

statycznych.

Wskaźniki i zmienne typu funkcyjnego nie mogą być lokalnymi dla wątków.

Typy, które używają techniki „copy-on-write” (jak AnsiString) mogą być
niebezpieczne jako typy zmiennych lokalnych dla wątku.

background image

Programowanie Obiektowe

124

Zmienna wymagająca inicjalizacji bądź finalizacji w trakcie działania
programu nie może być deklarowana jako

__thread

.

zmienna inicjalizowana poprzez wywołanie funkcji:

1

int f();

2

int __thread x = f();

// Bł ˛

ad!

obiekty typów klasowych definiujących konstruktor bądź destruktor

1

class X {

2

X();

3

~X();

4

};

5

X __thread myclass;

// Bł ˛

ad!

background image

Programowanie Obiektowe

125

Projektowanie obiektowe

Zrozumienie zadania

Algorytmy i struktury danych

Implementacja

Przykład: Zadanie Alice & Bob – konkurs programowania zespołowego ACM
– Europa Centralna 2001

background image

Programowanie Obiektowe

126

Technika top-down - zaczynamy od funkcji

main()

1

void main()

2

{

3

int ileZadan;

4

ZadanieAB ab;

5

fstream input(

"ab.in"

);

6

fstream output(

"ab.out"

, ios::out);

7

8

input >> ileZadan;

9

for (int i=0; i<ileZadan; i++)

10

{

11

input >> ab;

12

ab.Rozwiaz();

13

output << ab;

14

}

15

}

background image

Programowanie Obiektowe

127

Schemat klasy rozwiązującej zadanie:

1

class ZadanieAB

2

{

3

// Podstawowe dane

4

int n, m;

// liczby wierzchołków i przek ˛

atnych

5

Odcinki o;

// tablica odcinków

6

// Rezultaty

7

bool sukces;

8

int

numer;

// numery kolejnych wierzchołków

9

10

public:

11

bool Rozwiaz();

12

13

friend istream& operator>>(istream& is, ZadanieAB &ab);

14

friend ostream& operator<<(ostream& os, const ZadanieAB &ab);

15

};

background image

Programowanie Obiektowe

128

Szablony a przyjaciele

Norma języka nie przewiduje problemów.

Niestety, konkretne implementacje w problemy obfitują.

1

template<class T>

2

class task {

3

// ...

4

friend void next_time();

5

friend task<T>

preempt(task<T>

);

6

friend task

prmt(task

);

// task is task<T>

7

friend class task<int>;

8

// ...

9

};

background image

Programowanie Obiektowe

129

Zaprzyjaźniony operator – outline

1

template<class T>

2

class TempOp

3

{

4

T x;

5

public :

6

friend

7

ostream &operator <<(ostream &os, const TempOp<T> &to);

8

};

9

template<class T>

10

ostream &operator <<(ostream &os, const TempOp<T> &to)

11

{

12

os << to.x << endl;

13

return os;

14

}

Zgodne ze standardem, ale g++ akceptuje, u Borlanda problemy linkera!

background image

Programowanie Obiektowe

130

Zaprzyjaźniony operator – inline

1

template<class T>

2

class TempOp

3

{

4

T x;

5

public :

6

friend

7

ostream &operator <<(ostream &os, const TempOp<T> &to)

8

{

9

os << to.x << endl;

10

return os;

11

}

12

};

Zgodne ze standardem i akceptowane przez Borland C++ i g++.

background image

Programowanie Obiektowe

131

inline z ponowną deklaracją szablonu

1

template<class T>

2

class TempOp

3

{

4

T x;

5

public :

6

template <class P>

7

friend

8

ostream &operator <<(ostream &os, const TempOp<P> &to)

9

{

10

os << to.x << endl;

11

return os;

12

}

13

};

Może działać, ale nie jest to właściwa definicja.

background image

Programowanie Obiektowe

132

Działa, gdy mamy jedną specjalizację klasy:

1

TempOp<int> i;

2

cout << i;

Przestaje, gdy mamy więcej specjalizacji:

1

TempOp<double> to;

2

TempOp<int> i;

3

cout << to;

4

cout << i;

Kompilator zgłasza niejednoznaczność.

background image

Programowanie Obiektowe

133

STL – Standard Template Library

Teraz już jest częścią standardu języka.

Implementacja SGI

http://www.sgi.com/tech/stl/

wykorzystywana m.in. w Borland C++.

Implementuje szablony wielu bardzo przydatnych struktur danych i
algorytmów:

Kontenery:

vector, deque, list, set, multiset, map, multimap

, oraz

dodatkowo w implementacji SGI:

hash_set, hash_multiset, hash_map, hash_multimap

.

Iteratory

Algorytmy:

reverse, find, for_each, sort

. . .

background image

Programowanie Obiektowe

134

vector<T,Alloc>

Przykład:

1

vector<int> v;

2

v.reserve(100);

3

for (unsigned i=0; i<100; i++)

4

v[i] = i

i;

5

v.push_back(117);

6

for (unsigned i=0; i<v.size(); i++)

7

cout << v[i] << endl;

Parametry:

T

– typ elementów wektora

Alloc

– alokator pamięci

background image

Programowanie Obiektowe

135

Wybrane składowe:

reference

typ: referencja na

T

pointer

typ: wskaźnik na

T

iterator

typ do iterowania elementów

vector()

tworzy pusty wektor

vector(size_type n)

tworzy wektor

n

-wymiarowy

vector(size_type n, const T& t)

tworzy wektor z

n

kopii obiektu

t

iterator begin()

zwraca iterator wskazujący na początek

iterator end()

zwraca iterator wskazujący na koniec

reference front()

zwraca pierwszy element

reference back()

zwraca ostatni element

size_type size() const

zwraca rozmiar wektora

size_type capacity() const

ile zarezerwowanej pamięci (elementów)

reference operator[](size_type n)

zwraca n’ty element

void reserve(size_t n)

zapewnia

n

elementów wektora

void resize(n, t = T())

dodaje bądź usuwa by było

n

elementów

void push_back(const T&)

wstawia element na koniec

void pop_back()

usuwa ostatni element

iterator erase(iterator pos)

usuwa wskazany element

background image

Programowanie Obiektowe

136

Iteratory

Uogólnienie wskaźników.

Główny cel – sprawne poruszanie się po strukturach danych.

Przykład: wskaźniki istotnie szybciej pozwalają przebiec przez wszystkie
elementy tablicy niż iterowanie zmiennej całkowitej i dostęp do danych
przez

operator[]

:

1

const int n = 100000;

2

int tab[n];

3

// nieoptymalnie

4

for (int i=0; i<n; i++)

5

tab[i] = i;

// to samo co

(tab+i) = i;

6

// optymalnie

7

for (int i = n,

p=tab+n; p

−−

; )

8

p =

−−

i;

background image

Programowanie Obiektowe

137

Podejście naiwne:

1

template<class T>

2

class Vector

3

{

4

protected:

5

T

data;

6

int size;

7

public:

8

Vector(int s) {data=new T[size=s]; }

9

~Vector() {delete[] data;}

10

T &operator[] (int i) {return data[i];}

11

int Size() {return size;}

12

};

13

...

14

Vector<int> w;

15

...

16

for (int i=0; i<w.Size(); i++)

17

w[i] = i;

background image

Programowanie Obiektowe

138

Podejście z niepoprawnym iteratorem (wolniej niż naiwnie):

1

template<class T>

2

class Vector {

3

// ...

4

class Iterator {

5

T

ptr;

6

public:

7

Iterator(T

p) {ptr = p;}

8

T &operator

() {return

ptr;}

9

void operator ++() {ptr++;}

10

int operator <(const Iterator &i) {return ptr<i.ptr;}

11

};

12

Iterator begin() {return Iterator(data);}

13

Iterator end() {return Iterator(data+size);}

14

};

15

...

16

Vector<int>::Iterator it=w.begin(), e=w.end();

17

for (int i=0; it<e; it++)

18

it = i++;

background image

Programowanie Obiektowe

139

Podejście z poprawnym iteratorem:

1

template<class T>

2

class Vector

3

{

4

protected:

5

T

data;

6

int size;

7

public:

8

Vector(int s) {data=new T[size=s]; }

9

~Vector() {delete[] data;}

10

11

typedef T

Iterator;

12

Iterator begin() {return data;}

13

Iterator end() {return data+size;}

14

};

15

...

16

Vector<int>::Iterator it=w.begin(), e=w.end();

17

for (int i=0; it<e; it++)

18

it = i++;

background image

Programowanie Obiektowe

140

deque<T,Alloc>

Przykład:

1

deque<int> Q;

2

Q.push_back(3);

3

Q.push_front(1);

4

Q.insert(Q.begin() + 1, 2);

5

Q[2] = 0;

6

copy(Q.begin(), Q.end(), ostream_iterator<int>(cout,

" "

));

7

// Na wyj´sciu dostaniemy: 1 2 0

Parametry:

T

– typ elementów

Alloc

– alokator pamięci

background image

Programowanie Obiektowe

141

Niemal to samo co

vector

, ale dodaje i usuwa pierwszy element w stałym

czasie.

Nie posiada metod

capacity()

i

reserve()

.

Dodatkowe składowe:

void push_front(const T&)

wstawia element na początek

void pop_front()

usuwa pierwszy element

background image

Programowanie Obiektowe

142

list<T,Alloc>

Lista dwukierunkowa

Przykład:

1

list<int> L;

2

L.push_back(0);

3

L.push_front(1);

4

L.insert(++L.begin(), 2);

5

copy(L.begin(), L.end(), ostream_iterator<int>(cout,

" "

));

6

// Na wyj´sciu dostajemy: 1 2 0

Parametry:

T

– typ elementów listy

Alloc

– alokator pamięci

background image

Programowanie Obiektowe

143

Wybrane składowe:

reference

typ: referencja na

T

pointer

typ: wskaźnik na

T

iterator

typ do iterowania elementów

list()

tworzy pustą listę

list(size_type n)

tworzy listę

n

elementów

T()

list(size_type n, const T& t)

tworzy wektor z

n

kopii obiektu

t

iterator begin()

zwraca iterator wskazujący na początek

iterator end()

zwraca iterator wskazujący na koniec

reference front()

zwraca pierwszy element

reference back()

zwraca ostatni element

size_type size() const

zwraca rozmiar wektora

reference operator[](size_type n)

zwraca n’ty element

void reverse()

odwraca kolejność elementów

void push_back(const T&)

wstawia element na koniec

void remove(const T& value)

usuwa elementy równe

value

void merge(list& L)

łączy uporządkowane listy

void sort()

sortuje (stabilnie, złożoność nlogn)

background image

Programowanie Obiektowe

144

slist<T,Alloc>

Lista jednokierunkowa

Przykład:

1

slist<int> L;

2

L.push_front(0);

3

L.push_front(1);

4

L.insert_after(L.begin(), 2);

5

copy(L.begin(), L.end(),

// Na wyj´sciu 1 2 0

6

ostream_iterator<int>(cout,

" "

));

7

cout << endl;

8

9

slist<int>::iterator back = L.previous(L.end());

10

back = L.insert_after(back, 3);

11

back = L.insert_after(back, 4);

12

back = L.insert_after(back, 5);

13

copy(L.begin(), L.end(),

// Na wyj´sciu: 1 2 0 3 4 5

14

ostream_iterator<int>(cout,

" "

));

15

cout << endl;

background image

Programowanie Obiektowe

145

Mniej zajętej pamięci niż w

list

Większa złożoność pewnych operacji np

insert()

i

erase()

Lista metod niemal identyczna z

list

background image

Programowanie Obiektowe

146

set<Key, Compare, Alloc>

Implementacja zbioru reprezentowanego w sposób uporządkowany dla
sprawniejszej obsługi, wstawianie jednego (uporządkowanego) zbioru do
drugiego jest bardzo szybkie itp.

Prosty kontener asocjacyjny – klucze i wartości (tutaj tożsame)

Parametry:

Key

– typ elementów zbioru (kluczy i wartości)

Compare

– funkcja porównująca zdefiniowana jako klasa

Alloc

– alokator pamięci

Przykład:

1

struct ltstr

2

{

3

bool operator()(const char

s1, const char

s2) const

4

{

5

return strcmp(s1, s2) < 0;

6

}

7

};

8

background image

Programowanie Obiektowe

147

9

int main()

10

{

11

const int N = 6;

12

const char

a[N] = {

"isomer"

,

"ephemeral"

,

"prosaic"

,

13

"nugatory"

,

"artichoke"

,

"serif"

};

14

const char

b[N] = {

"flat"

,

"this"

,

"artichoke"

,

15

"frigate"

,

"prosaic"

,

"isomer"

};

16

17

set<const char

, ltstr> A(a, a + N);

18

set<const char

, ltstr> B(b, b + N);

19

set<const char

, ltstr> C;

20

21

cout <<

"Set A: "

;

22

copy(A.begin(), A.end(), ostream_iterator<const char

>(cout,

" "

));

23

cout << endl;

24

cout <<

"Set B: "

;

25

copy(B.begin(), B.end(), ostream_iterator<const char

>(cout,

" "

));

26

cout << endl;

27

background image

Programowanie Obiektowe

148

28

cout <<

"Union: "

;

29

set_union(A.begin(), A.end(), B.begin(), B.end(),

30

ostream_iterator<const char

>(cout,

" "

),

31

ltstr());

32

cout << endl;

33

34

cout <<

"Intersection: "

;

35

set_intersection(A.begin(), A.end(), B.begin(), B.end(),

36

ostream_iterator<const char

>(cout,

" "

),

37

ltstr());

38

cout << endl;

39

40

set_difference(A.begin(), A.end(), B.begin(), B.end(),

41

inserter(C, C.begin()),

42

ltstr());

43

cout <<

"Set C (difference of A and B): "

;

44

copy(C.begin(), C.end(), ostream_iterator<const char

>(cout,

" "

));

45

cout << endl;

46

}

background image

Programowanie Obiektowe

149

multiset<Key, Compare, Alloc>

Podobnie jak w

set

, ale z możliwymi powtórzeniami elementów

Przykład:

1

int main()

2

{

3

const int N = 10;

4

int a[N] = {4, 1, 1, 1, 1, 1, 0, 5, 1, 0};

5

int b[N] = {4, 4, 2, 4, 2, 4, 0, 1, 5, 5};

6

7

multiset<int> A(a, a + N);

8

multiset<int> B(b, b + N);

9

multiset<int> C;

10

11

cout <<

"Set A: "

;

12

copy(A.begin(), A.end(), ostream_iterator<int>(cout,

" "

));

13

cout << endl;

14

cout <<

"Set B: "

;

15

copy(B.begin(), B.end(), ostream_iterator<int>(cout,

" "

));

background image

Programowanie Obiektowe

150

16

cout << endl;

17

18

cout <<

"Union: "

;

19

set_union(A.begin(), A.end(), B.begin(), B.end(),

20

ostream_iterator<int>(cout,

" "

));

21

cout << endl;

22

23

cout <<

"Intersection: "

;

24

set_intersection(A.begin(), A.end(), B.begin(), B.end(),

25

ostream_iterator<int>(cout,

" "

));

26

cout << endl;

27

28

set_difference(A.begin(), A.end(), B.begin(), B.end(),

29

inserter(C, C.begin()));

30

cout <<

"Set C (difference of A and B): "

;

31

copy(C.begin(), C.end(), ostream_iterator<int>(cout,

" "

));

32

cout << endl;

33

}

background image

Programowanie Obiektowe

151

map<Key, Data, Compare, Alloc>

Posortowany kontener asocjacyjny przypisujący obiektom typu

Key

(kluczom) obiekty typu

Data

(wartości).

Kontener par

pair<const Key, Data>

.

Klucze muszą być unikalne.

Parametry:

Key

– typ kluczy

Data

– typ wartości

Compare

– funkcja porównująca klucze

Alloc

– alokator pamięci

Przykład:

1

struct ltstr

2

{

3

bool operator()(const char

s1, const char

s2) const

4

{

5

return strcmp(s1, s2) < 0;

6

}

7

};

background image

Programowanie Obiektowe

152

8

9

int main()

10

{

11

map<const char

, int, ltstr> months;

12

13

months[

"january"

] = 31;

14

months[

"february"

] = 28;

15

months[

"march"

] = 31;

16

months[

"april"

] = 30;

17

months[

"may"

] = 31;

18

months[

"june"

] = 30;

19

months[

"july"

] = 31;

20

months[

"august"

] = 31;

21

months[

"september"

] = 30;

22

months[

"october"

] = 31;

23

months[

"november"

] = 30;

24

months[

"december"

] = 31;

25

26

cout <<

"june

> "

<< months[

"june"

] << endl;

background image

Programowanie Obiektowe

153

27

map<const char

, int, ltstr>::iterator cur = months.find(

"june"

);

28

map<const char

, int, ltstr>::iterator prev = cur;

29

map<const char

, int, ltstr>::iterator next = cur;

30

++next;

31

−−

prev;

32

cout <<

"Previous (in alphabetical order) is "

33

<< (

prev).first << endl;

34

cout <<

"Next (in alphabetical order) is "

35

<< (

next).first << endl;

36

}

background image

Programowanie Obiektowe

154

multimap<Key, Compare, Alloc>

Podobnie jak w

map

, ale z możliwymi powtórzeniami kluczy

Przykład:

1

struct ltstr

2

{

3

bool operator()(const char

s1, const char

s2) const

4

{

5

return strcmp(s1, s2) < 0;

6

}

7

};

8

9

int main()

10

{

11

multimap<const char

, int, ltstr> m;

12

13

m.insert(pair<const char

const, int>(

"a"

, 1));

14

m.insert(pair<const char

const, int>(

"c"

, 2));

15

m.insert(pair<const char

const, int>(

"b"

, 3));

background image

Programowanie Obiektowe

155

16

m.insert(pair<const char

const, int>(

"b"

, 4));

17

m.insert(pair<const char

const, int>(

"a"

, 5));

18

m.insert(pair<const char

const, int>(

"b"

, 6));

19

20

cout <<

"Number of elements with key a: "

<< m.count(

"a"

) << endl;

21

cout <<

"Number of elements with key b: "

<< m.count(

"b"

) << endl;

22

cout <<

"Number of elements with key c: "

<< m.count(

"c"

) << endl;

23

24

cout <<

"Elements in m: "

<< endl;

25

for (multimap<const char

, int, ltstr>::iterator it = m.begin();

26

it != m.end();

27

++it)

28

cout <<

" ["

<< (

it).first <<

", "

<< (

it).second <<

"]"

<< endl;

29

}

background image

Programowanie Obiektowe

156

Platforma .NET

.NET Framework = Common Language Runtime (CLR) + Framework
Class Library (FCL)

Środowisko a kompilatory

MSIL - MicroSoft Intermediate Language (Common Intermediate
Language - CIL)

wspólny kod wyjściowy dla różnych jezyków programowania (Visual
Basic, C#, Managed C++, JScript. . . )

każdy program można łatwo zdekompilować

programy utrudniające dekompilację - obfuscators

JIT (Just in Time) compiler

tworzy kod maszynowy dla danego procesora (jak w Javie)

optymalizacja na dany komputer – bardzo poważna zaleta

background image

Programowanie Obiektowe

157

Platforma .NET – c.d.

Zarządzanie bibliotekami dynamicznymi

Zestaw (assembly) jako uogólnienie DLL

Zezwolenie na wiele wersji tego samego zestawu

bogactwo biblioteki standardowej .NET (FCL) – przestrzenie nazw
nabierają jeszcze większego znaczenia

projekt MONO

http://www.mono-project.com/

- .NET na Unix’ach

background image

Programowanie Obiektowe

158

Język C# – podstawy

Brak plików nagłówkowych, bardzo szybka kompilacja

Wszystko wewnątrz klas

Identyfikatory to ciągi znaków Unicode (mogą zawierać polskie znaki)

Operator . zamiast ::

Pierwszy program

1

class Example

2

{

3

public static void Main () {

4

System.Console.WriteLine (

"Hello world!"

);

5

}

6

}

Dostęp definiowany przy każdej składowej

Średniki po deklaracjach klas niepotrzebne

background image

Programowanie Obiektowe

159

Przestrzenie nazw

Deklaracje dokładania do przestrzeni i korzystanie z przestrzeni

1

namespace Poczatki {

2

using System;

3

class Example {

4

public static void Main () {

5

Console.WriteLine (

"Hello world!"

);

6

}

7

}

8

}

Można zagnieżdżać przestrzenie nazw tworząc hierarchię

Przykłady z hierarchii FCL

1

System.IO

2

System.Collections.Generic

3

System.Runtime.Serialization.Formatters.Binary

4

System.Security.Cryptography

background image

Programowanie Obiektowe

160

Typy wartościowe i referencyjne

Stos i sterta (stack and heap)

stos – obsługa wywołań funkcji i zmiennych lokalnych

sterta – miejsce na dynamicznie alokowane zmienne

czyszczenie stosu związane z powrotami z funkcji

czyszczenie sterty przejmuje system zbierania odpadków (garbage
collection)

Typy wartościowe (typy proste,

struct

,

enum

)

1

class Test {

2

static void Main () {

3

int x = 3;

4

int y = x;

// assign x to y, y is now a copy of x

5

x++;

// increment x to 4

6

System.Console.WriteLine (y);

// prints 3

7

}

8

}

background image

Programowanie Obiektowe

161

Typy referencyjne (klasy, kolekcje, delegacje, interfejsy)

wartość i adres jej przechowywania w jednym

analogicznie do przekazywania parametrów przez referencję w C++

syntaktycznie jak wartości, semantycznie jak wskaźniki

1

using System;

2

using System.Text;

3

class Test {

4

static void Main () {

5

StringBuilder x = new StringBuilder (

"hello"

);

6

StringBuilder y = x;

7

x.Append (

" there"

);

8

Console.WriteLine (y);

// prints "hello there"

9

}

10

}

background image

Programowanie Obiektowe

162

typy wartościowe i referencyjne - przykład porównujący

1

class PointR {

// typ referencyjny

2

public int x, y;

3

}

4

struct PointV {

// typ warto´

sciowy

5

public int x, y;

6

}

7

class Test {

8

static void Main() {

9

PointR a;

// 4 bajty na stosie

10

PointV b;

// 8 bajtów na stosie

11

a = new PointR();

// alokacja 8 bajtów na stercie

12

b = new PointV();

// zawołanie konstruktora

13

a.x = 7;

14

b.x = 7;

15

}

16

}

background image

Programowanie Obiektowe

163

opakowywanie wartości w obiekty referencyjne i rozpakowywanie (boxing,
unboxing)

1

class Test {

2

static void Main () {

3

int x = 9;

4

object o = x;

// box the int

5

int y = (int)o;

// unbox the int

6

}

7

}

background image

Programowanie Obiektowe

164

Predefiniowane typy wartościowe

typy całkowite

alias

typ

rozmiar

znak

sbyte

System.SByte

1

tak

short

System.Int16

2

tak

int

System.Int32

4

tak

long

System.Int64

8

tak

byte

System.Byte

1

nie

ushort

System.UInt16

2

nie

uint

System.UInt32

4

nie

ulong

System.UInt64

8

nie

1

int ii = 5;

2

uint ui = 5U;

3

long ll = 5L;

4

ulong ul = 5UL;

background image

Programowanie Obiektowe

165

typy rzeczywiste

alias

typ

rozmiar

float

System.Single

4

double

System.Double

8

decimal

System.Decimal

16

1

float f = 3.14f;

2

double d = 3.14;

3

decimal m = 123456789.123456789m;

typ

decimal

:

28-29 cyfr znaczących, ale mały zakres

szczególnie przydatny w finansach

char

i

bool

alias

typ

rozmiar

char

System.Char

2

bool

System.Boolean

1/2

background image

Programowanie Obiektowe

166

Predefiniowane typy referencyjne

alias

typ

rozmiar

object

System.Object

0/8

string

System.String

min. 20

object

– klasa bazowa dla wszystkich typów, dla referencyjnych 8 bajtów

string

– niezmienna sekwencja znaków Unicode

string

– zwykła klasa o specjalnym traktowaniu

1

string a1 =

"\\\\server\\fileshare\\helloworld.cs"

;

2

string a2 = @

"\\server\fileshare\helloworld.cs"

;

3

Console.WriteLine(a1==a2);

// Prints "True"

4

string b1 =

"First Line\r\nSecond Line"

;

5

string b2 = @

"First Line

6

Second Line"

;

7

Console.WriteLine(b1==b2);

// Prints "True"

background image

Programowanie Obiektowe

167

Garbage collection

new

- alokacja jak w C++

nie zwalniamy pamięci wprost (na wzór

delete

z C++)

garbage collection system – system zarządzania pamięcią

zarządza wszelkimi referencjami do obiektów

odzyskuje pamięć po niepotrzebnych obiektach

Uwaga! ważne zerowanie „długo żyjących” referencji, bo inaczej
wycieki pamięci

Uwaga! obiekty mogą zmieniać swoje położenie (adres) bez wiedzy
programisty

1

public void Test()

2

{

3

Macierz m = new Macierz();

4

m = null;

// dla zmiennych lokalnych niepotrzebne

5

}

background image

Programowanie Obiektowe

168

Garbage collection

1

// W klasie Macierz

2

public Macierz(Manager mgr)

3

{

4

mgr.Rejestruj(this);

// mgr wrzuca this do kolekcji

5

...

6

}

7

public void Test(Manager mgr)

8

{

9

Macierz m = new Macierz(mgr);

10

...

11

// m nie b˛

edzie zwolniona, bo "trzyma" j ˛

a mgr

12

}

background image

Programowanie Obiektowe

169

Typ wyliczeniowy

Standardowo wartości 0, 1, 2, . . .

1

enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri};

Wartości 1, 2, . . .

1

enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};

Wartości jawnie zadane i typ

long

:

1

enum Range : long {Max = 2147483648L, Min = 255L};

Brak konwersji niejawnych - trzeba jawnie

1

int i = (int)Days.Sun;

2

long l = (long)Range.Max;

Dostępne operatory:

== != < > <= >= + - ^ & | ~ = += -= ++ --

sizeof

background image

Programowanie Obiektowe

170

Tablice

System.Array

– zwykła klasa o specjalnym traktowaniu

syntaktyka podobna do C++, ale z pewnymi różnicami

tablice prostokątne i „postrzępione” (jagged)

1

int[] tab, tab2 = new int[15];

2

int[,] tab2d = new int[5,5];

3

double[][] macierz = new double[5][];

4

for (int i=0; i<5; i++)

5

macierz[i] = new int[10+i];

6

tab2[5] = tab2d[0,3] = 7;

7

macierz[0][3] = 7;

8

int[,] zainicjowana = {{1,2},{3,4}};

kontrola zakresów, wyjątek

IndexOutOfRangeException

, dzięki

optymalizacji nie musi dużo kosztować

background image

Programowanie Obiektowe

171

Wybrane metody i własności klasy Array

Length

długość tablicy

Rank

liczba wymiarów

IsReadOnly

czy tylko do odczytu

GetLength()

długość w danym wymiarze

GetLowerBound()

dolne ograniczenie danego wymiaru

GetUpperBound()

górne ograniczenie danego wymiaru

Sort()

sortowanie tablic jednowymiarowych

Reverse()

odwracanie kolejności tablic jednowymiarowych

IndexOf()

indeks pierwszego wystąpienia wartości

LastIndexOf()

indeks ostatniego wystąpienia wartości

Copy()

kopiowanie fragmentu

Clear()

ustawianie wartości 0 lub

null

background image

Programowanie Obiektowe

172

Zmienne

ściśle określony typ (operacje, które można wykonywać)

każda zmienna musi być zainicjowana przed użyciem

wartości domyślne dla pól obiektów złożonych

numeryczne i wyliczeniowe –

0

char –

’\0’

bool –

false

referencyjne –

null

background image

Programowanie Obiektowe

173

Przekazywanie argumentów do metod

domyślnie przez wartość (działania na kopii)

w przypadku typów referencyjnych – kopia referencji

ref

– przekazanie przez referencję

1

public void zamie´

n(ref int a, ref int b)

2

{

3

int c = a;

4

a = b;

5

b = c;

6

}

background image

Programowanie Obiektowe

174

out

– parametr traktowany jak wyjście funkcji, kompilator pilnuje by

zmiennej coś przypisać w funkcji

1

public void ustaw(out int a, out int b)

2

{

3

a = 5;

4

b = 7;

// skomentuj jedn ˛

a z linii by dosta´

c bł ˛

ad

5

}

background image

Programowanie Obiektowe

175

ref

i

out

konieczne również przy wywołaniach

zmienna przekazana z modyfikatorem

out

może nie być zainicjowana

1

public void test()

2

{

3

int x, y;

4

ustaw(out x, out y);

5

zamie´

n(ref x, ref y);

6

}

nie ma mechanizmu domyślnych wartości parametrów metod, trzeba
jawnie przeciążać metody, by uzyskać ten sam efekt

1

public int Kalkuluj(int a, int b) { return ... }

2

public int Kalkuluj(int a) { return Kalkuluj(a, 0); }

background image

Programowanie Obiektowe

176

Modyfikatory dostępu

public

– „pełna widoczność”

private

– dostęp tylko dla metod tej samej klasy

protected

– dostęp dla metod tej samej klasy i klas potomnych

internal

– dostęp w ramach zestawu (assembly)

protected internal

– suma logiczna warunków dostępu dla

protected

i

internal

domyślnie:

dla niezagnieżdżonych klas

internal

dla składowych klas

private

dziedziczenie zawsze publiczne!

background image

Programowanie Obiektowe

177

Pola klas

pola mogą być inicjowane w linii deklaracji (przypisanie nastąpi przed
konstruktorem)

1

public class test

2

{

3

internal string kto =

"Ala"

;

4

public string KtoTo() { return kto; }

5

}

pola statyczne są alokowane i inicjowane dopiero wtedy, gdy są potrzebne

pola tylko do odczytu

1

readonly int rozmiar = 100;

2

static readonly maxRozmiar = 1000;

wyznaczane w trakcie działania, nie kompilacji

muszą być zainicjowane w linii deklaracji bądź w konstruktorze

background image

Programowanie Obiektowe

178

pola stałe

1

public const double PI = 3.14159265358979323846;

wyznaczane w trakcie kompilacji

statyczne z założenia

dozwolone typy:

sbyte

,

byte

,

short

,

ushort

,

int

,

uint

,

long

,

ulong

,

float

,

double

,

decimal

,

bool

,

char

,

string

,

enum

muszą być zainicjowane w linii deklaracji bądź w konstruktorze

background image

Programowanie Obiektowe

179

Własności (properties)

implementowane inline

1

public class Prostok ˛

at

2

{

3

int lewa, góra, długo´

c, szeroko´

c;

4

public int Prawa {

5

get { return lewa + dlugo´

c; }

6

set ( lewa = value - dlugo´

c; }

7

}

8

}

w praktyce para metod

get_Prawa()

i

set_Prawa(int value)

background image

Programowanie Obiektowe

180

Operatory indeksujące (indexers)

definiowane podobnie do własności

1

public class Tab5Double {

2

double[] tab = new double[5];

3

double suma;

4

public double this[int i] {

5

get { return tab[i]; }

6

set { suma += value-tab[i]; tab[i] = value; }

7

}

8

public double Srednia {

9

get { return suma / 5; }

10

}

11

}

można zdefiniować wiele operatorów o różnych listach argumentów

background image

Programowanie Obiektowe

181

Konstruktory klas

jak w C++ tj. metody o nazwie klasy

1

public class TabDouble {

2

double[] tab;

3

TabDouble(int n) { tab = new double[n]; }

4

TabDouble() : this(n) {};

5

}

pola inicjowane w linii deklaracji przychodzą do konstruktora już
zainicjowane (w kolejności występowania w klasie)

mogą być opatrzone dowolnym modyfikatorem dostępu

background image

Programowanie Obiektowe

182

Konstruktor statyczny

może być tylko jeden w klasie

wołany przed stworzeniem pierwszego obiektu i przed dostępem do
jakiegokolwiek pola statycznego klasy

1

public class TabDouble {

2

static TabManager tabmgr;

3

static TabDouble() { tabmgr = new TabManager(); }

4

}

pola statyczne inicjalizowane przed konstruktorem statycznym

kolejność wołania konstruktorów statycznych jest nieustalona, również
dziedziczenie nie ma tu znaczenia

background image

Programowanie Obiektowe

183

Destruktor

Jak w C++ metoda o nazwie klasy poprzedzonej tyldą

Zadania całkiem inne niż w C++ ze względu na garbage collection

Bardzo rzadko potrzebne

Czas wykonania destruktora jest nieokreślony

Kompilowany do funkcji wirtualnej

Finalize()

1

protected override void Finalize() {

2

...

3

base.Finalize();

4

}

background image

Programowanie Obiektowe

184

Dziedziczenie

Klasa bez jawnego dziedziczenia dziedziczy po

object

Wielokrotne dziedziczenie jest niedozwolone

Prosty przykład:

1

public class Kwadrat : Prostok ˛

at {

2

public Kwadrat(int lewa, int góra, int bok)

3

: base(lewa, góra, bok, bok)

4

{

5

}

6

public Okr ˛

ag Okr ˛

agWpisany();

7

}

background image

Programowanie Obiektowe

185

Konwersje niejawne dozwolone tylko w stronę bazowej

1

Kwadrat k = new Kwadrat(0, 0, 5);

2

Prostok ˛

at p = k;

// OK

3

Kwadrat w = (Kwadrat)p;

// jawna konwersja konieczna

Nieudana jawna konwersja oznacza wyjątek

InvalidCastException

Operator

as

(w wyniku

null

, gdy się nie uda)

1

Kwadrat w = p as Kwadrat;

Operator

is

(pytanie o dziedziczenie lub implementację interfejsu)

1

if (p is Kwadrat)

2

((Kwadrat)p).OkragWpisany().Rysuj();

background image

Programowanie Obiektowe

186

Polimorfizm

Polimorfizm to możliwość realizacji tego samego wywołania w kontekście
wielu typów.

Dziedziczenie klas i implementowanie interfejsów

Metody wirtualne

1

public class Figura {

2

public virtual void Rysuj() {throw new NotDefined();}

3

}

4

public class Prostok ˛

at : Figura {

5

public override void Rysuj() {...}

6

}

7

public class Kwadrat : Prostok ˛

at {

8

public override void Rysuj() {...}

9

}

background image

Programowanie Obiektowe

187

Klasy abstrakcyjne

Klasy abstrakcyjne mogą zawierać metody abstrakcyjne

Metody abstrakcyjne to metody wirtualne bez implementacji:

1

public abstract class Figura {

2

public abstract void Rysuj();

3

}

W C++

1

class Figura {

2

public:

3

virtual void Rysuj() = 0;

4

}

background image

Programowanie Obiektowe

188

Ukrywanie metod wirtualnych – przerywanie wirtualności

1

public class Figura {

2

public virtual void Rysuj() {throw new NotDefined();}

3

}

4

public class Prostok ˛

at : Figura {

5

public override void Rysuj() {...}

6

}

7

public class Kwadrat : Prostok ˛

at {

8

public new void Rysuj() {...}

9

}

Wówczas:

1

Kwadrat k = new Kwadrat(0, 0, 5);

2

k.Rysuj();

// woła Kwadrat.Rysuj()

3

((Figura)k).Rysuj();

// woła Prostok ˛

at.Rysuj()

background image

Programowanie Obiektowe

189

Modyfikator

sealed

– klasy i metody „zalakowane”

Nie można dziedziczyć po zalakowanej klasie

1

public sealed class Prostok ˛

at : Figura {

2

...

3

}

4

public class Kwadrat : Prostok ˛

at {

// Bł ˛

ad!

5

...

6

}

Pozwala kompilatorowi zmienić wywołania wirtualne na niewirtualne

Zwykle dla klas zawierających tylko statyczne metody (np. Math)

Można zalakować pojedyńcze metody

1

public class Prostok ˛

at : Figura {

2

public sealed override Rysuj() {...}

3

}

background image

Programowanie Obiektowe

190

Słowo kluczowe base

Daje dostęp do metod klasy bazowej

Podobne w użyciu jak słowo kluczowe

this

:

1

public class Prostok ˛

at : Figura {

2

public Prostok ˛

at(int x, int y, int dług, int szer) {...}

3

public override void Rysuj() {...}

4

}

5

public class Kwadrat : Prostok ˛

at {

6

public Kwadrat(int x, int y, int bok)

7

: base(x, y, bok, bok) {...}

8

public Kwadrat(int bok)

9

: this(0, 0, bok) {...}

10

public override void Rysuj() {

11

base.Rysuj(); ...

12

}

13

}

background image

Programowanie Obiektowe

191

Interfejsy

Interfejsy to specyfikacje możliwości klas (główne narzędzie polimorfizmu
w C#)

Klasy i struktury mogą implementować interfejsy tzn. implementować
wszystko co wyspecyfikowane w ramach interfejsu

Konstrukcje podobne do klas z kilkoma bardzo istotnymi różnicami:

Interfejsy nie zawierają implementacji żadnych metod (są trochę jak
klasy abstrakcyjne zawierające wyłącznie deklaracje abstrakcyjnych
metod)

Klasy i struktury mogą implementować wiele interfejsów

Struktury mogą implementować interfejsy, ale nie mogą dziedziczyć klas

Interfejsy mogą zawierać deklaracje:

metod,

własności,

operatorów indeksujących,

zdarzeń.

background image

Programowanie Obiektowe

192

Definicja interfejsu

1

public interface ICloneable {

2

object Clone();

3

}

Interfejs może rozszerzać inne interfejsy:

1

public interface ITablica {

2

object this[int i] { get; set; }

3

}

4

public interface ISortowalnaTablica : ITablica {

5

void Sortuj();

6

}

background image

Programowanie Obiektowe

193

Implementacja interfejsu

1

public class TablicaInt : ISortowalnaTablica {

2

public object this[int i] { get { return 0;} set {} }

3

public void Sortuj() { }

4

}

Implementacja interfejsu w sposób jawny (np. żeby uniknąć konfliktu, gdy
dwa interfejsy zawierają taką samą składową)

1

public class TablicaCalkowitych : ISortowalnaTablica {

2

object ITablica.this[int i] { get {return 1;} set {} }

3

void ISortowalnaTablica.Sortuj() { }

4

}

Dziedziczenie i implementacja – najpierw klasa, potem interfejsy

1

public class Kwadrat : Prostok ˛

at, ICloneable {

2

...

3

}

background image

Programowanie Obiektowe

194

Reimplementacja interfejsu

Jeśli klasa bazowa implementuje składową interfejsu jako wirtualną, to
klasy potomne mogą je dociążać:

1

public class Bazowa : ICloneable {

2

public virtual object Clone() {return new Bazowa();}

3

}

4

public class Potomna : Bazowa {

5

public override object Clone() {return new Potomna();}

6

}

Uwaga na

virtual

/

override

!

Jeśli w powyższym

Clone

zabraknie

virtual

/

override

, to:

1

Potomna co´

s = new Potomna();

2

(co´

s as ICloneable).Clone();

// woła Bazowa.Clone()

background image

Programowanie Obiektowe

195

Można też reimplementować interfejs:

1

public class Bazowa : ICloneable {

2

public object Clone() {return new Bazowa();}

3

}

4

public class Potomna : Bazowa, ICloneable {

5

public object Clone() {return new Potomna();}

6

}

Wówczas:

1

Potomna co´

s = new Potomna();

2

(co´

s as ICloneable).Clone();

// woła Potomna.Clone()

background image

Programowanie Obiektowe

196

Delegaty

Sygnatury metod – typy do przechowywania i wołania metod
(pojedyńczych bądź list metod) o określonej liście parametrów

1

delegate Figura Transformacja(Figura f);

2

class KolekcjaFigur {

3

Figura[] figury;

4

KolekcjaFigur Transformuj(Transformacja t)

5

{

6

KolekcjaFigur kf = new KolekcjaFigur(liczbaFigur);

7

foreach (Figura f in Figury)

8

kf.Dodaj(t(f));

9

return kf;

10

}

11

}

background image

Programowanie Obiektowe

197

Argumenty mogą być specyfikowane z modyfikatorem

params

1

delegate int Kombinacja(params int[] arg);

2

class Operacje

3

{

4

static public int Suma(params int[] argumenty) {

5

int wynik = 0;

6

foreach (int i in argumenty)

7

wynik += i;

8

return wynik;

9

}

10

static public void Main() {

11

Kombinacja k = new Kombinacja(Suma);

12

System.Console.WriteLine(

"Wynik = {0}"

, k(1, 2, 3, 4));

13

}

14

}

background image

Programowanie Obiektowe

198

Operatory

+=

i

-=

do obsługi delegatów przechowujących listy metod

1

delegate int Kombinacja(params int[] arg);

2

class Operacje

3

{

4

static public int Suma(params int[] argumenty) { ... }

5

static public int Iloczyn(params int[] argumenty) { ... }

6

static public void Main() {

7

Kombinacja k = new Kombinacja(Suma);

8

k += Iloczyn;

9

//k -= Suma;

10

System.Console.WriteLine(

"Wynik = {0}"

, k(1, 2, 3, 4));

11

}

12

}

Kolejność wołania taka jak kolejność dodawania.

Delegat zwraca wynik ostatniej metody z listy.

background image

Programowanie Obiektowe

199

Zdarzenia

Interfejsy graficzne sterowane zdarzeniami.

Delegaty – doskonały środek do realizacji obsługi zdarzeń.

Konwencja: pierwszy argument to źródło, drugi to parametry zdarzenia
(dziedziczy po

System.EventArgs

):

1

delegate void MoveEventHandler(object source,

2

MoveEventArgs e);

Przykład parametrów zdarzenia:

1

public class MoveEventArgs : EventArgs {

2

public int newPosition;

3

public bool cancel;

4

public MoveEventArgs(int newPosition) {

5

this.newPosition = newPosition;

6

}

7

}

background image

Programowanie Obiektowe

200

Przykład uruchomienia zdarzenia:

1

class Slider {

2

int position;

3

public event MoveEventHandler Move;

4

public int Position {

5

get { return position; }

6

set {

7

if (Move != null) {

// if invocation list not empty

8

MoveEventArgs args = new MoveEventArgs(value);

9

Move(this, args);

// fire event

10

if (args.cancel) return;

11

}

12

position = value;

13

}

14

}

15

}

background image

Programowanie Obiektowe

201

Zestawy (ang. assembly)

Nowe podejście do bibliotek alokowanych dynamicznie.

Różne wersje tej samej biblioteki mogą równolegle funkcjonować w
systemie.

Zestaw może stanowić pojedynczy moduł (plik .dll lub .exe), albo kilka
modułów (słabe wsparcie).

Nie mylić z przestrzeniami nazw (ang. namespaces), choć często ta sama
nazwa jest użyta i dla zestawu i przestrzeni nazw.

Silne nazwy (strong names) – unikalne, generowane przy użyciu klucza
prywatnego

Global Assembly Cache – magazyn zestawów

background image

Programowanie Obiektowe

202

Application domains

Proces = uruchomiona aplikacja.

System chroni procesy przed innymi procesami.

Domeny pozwalają na podobną ochronę w ramach jednego procesu.

Proces startuje z jedną domyślną domeną, dodatkowe można tworzyć
samemu w miarę potrzeby.

Wymiana danych pomiędzy domenami na tych samych zasadach co
między procesami.

Wiele wątków może biec w ramach jednej domeny.

Jeden wątek może pracować w ramach różnych domen (ale nie
jednocześnie).

background image

Programowanie Obiektowe

203

Głowne składowe klasy

AppDomain

:

CurrentDomain

– statyczna własność, zwraca bieżącą domenę dla

bieżącego wątku

CreateDomain()

– tworzy nową domenę

GetCurrentThreadID()

– identyfikator bieżącego wątku

Load()

ładuje zestaw do domeny

Unload()

– usuwa zadaną domenę

CreateInstance()

– tworzy obiekt w domenie

background image

Programowanie Obiektowe

204

Przykład:

1

AppDomain ad2 =

2

AppDomain.CreateDomain(

"Shape Domain"

);

3

ObjectHandle oh = ad2.CreateInstance(

4

"ProgCSharp"

,

// the assembly name

5

"ProgCSharp.Shape"

,

// the type name with namespace

6

false,

// ignore case

7

System.Reflection.BindingFlags.CreateInstance,

// flag

8

null,

// binder

9

new object[] {3, 5},

// args

10

null,

// culture

11

null,

// activation attributes

12

null );

// security attributes

background image

Programowanie Obiektowe

205

Atrybuty

Służą do opisywania elementów składniowych: zestaw, klasa, konstruktor,
delegat, typ wyliczeniowy, zdarzenie, pole, interfejs, metoda, moduł,
parametr, własność, wartość zwracana, struktura

Meta-dane o klasach, polach itd.

Przykłady:

1

[assembly: AssemblyKeyFile(

"c:\\myStrongName.key"

)]

2

[NoIDispatch]

3

public interface IEksperymentCOM {...}

4

[Serializable]

5

class MySerializableClass { ...}

Wstawia się je bezpośrednio przed deklaracją, której dotyczą, z wyjątkiem
tych dotyczących zestawów i modułów.

Atrybuty wewnętrzne – wsparcie Common Language Runtime,
zintegrowane z .NET

background image

Programowanie Obiektowe

206

Atrybuty użytkownika – klasy dziedziczące po

System.Attribute

1

public class MachineAttribute : Attribute

2

{

3

public string name;

4

public Type configType;

5

public MachineAttribute(string name, Type configType)

6

{

7

this.name = name;

8

this.configType = configType;

9

}

10

}

11

12

[Machine(

"Decision tree"

, typeof(DTConfig))]

13

public class DT : DTClassifier, IMachine

14

{ ... }

background image

Programowanie Obiektowe

207

Konwencja wspierana przez kompilator: nazwy klas kończą się na

Attribute

Koniecznie przynajmniej jeden konstruktor.

Parametry pozycyjne (argumenty konstruktora)

Parametry nazwane (własności)

1

[Machine(

"Decision tree"

, typeof(DTConfig),

2

Description=

"A standard greedy search decision tree"

)]

Atrybut atrybutów (meta-atrybut)

1

[AttributeUsage(AttributeTargets.Class,

2

AllowMultiple = false)]

3

public class MachineAttribute : Attribute

4

{ ... }

Wiele atrybutów można wymienić w jednym nawiasie kwadratowym:

1

[Serializable, Machine(...)]

background image

Programowanie Obiektowe

208

Mechanizm refleksji (reflection)

Dostęp do meta-danych.

Duże możliwości penetrowania hierarchii klas, wnętrz klas itd.

Klasa

Type

– meta-dane o typach i ich wnętrznościach

Pobieranie informacji o typie

1

Type t = zmienna.GetType();

// metoda System.Object

2

Type t = Type.GetType(

"System.Int32"

);

3

Type t2 = Type.GetType(

"MyNamespace.MyType"

, MyAssembly);

4

Type t3 = typeof(System.Int32);

background image

Programowanie Obiektowe

209

Przykład penetracji typów:

1

using System;

2

using System.Reflection;

3

class Test {

4

static void Main( ) {

5

DumpTypeInfo((new Object()).GetType( ));

6

DumpTypeInfo(typeof(int));

7

DumpTypeInfo(Type.GetType(

"System.String"

));

8

}

9

static void DumpTypeInfo(Type t) {

10

Console.WriteLine(

"Type: {0}"

, t);

11

// Retrieve the list of members in the type

12

MemberInfo[ ] miarr = t.GetMembers( );

13

// Print out details on each of them

14

foreach (MemberInfo mi in miarr)

15

Console.WriteLine(

" {0}={1}"

, mi.MemberType, mi);

16

}

17

}

background image

Programowanie Obiektowe

210

Inne możliwości mechanizmów refleksji:

late binding – ładowanie bibliotek, tworzenie obiektów i wołanie metod na
etapie działania programu a nie kompilacji – Uwaga! znacznie wolniej!

Modyfikacja pól prywatnych.

Tworzenie typów na etapie działania programu
(

System.Reflection.Emit

), klasy:

AssemblyBuilder

– dynamiczne tworzenie zestawów,

ModuleBuilder

– dynamiczne tworzenie modułów,

TypeBuilder

– dynamiczne tworzenie typów,

ILGenerator

– dynamiczne tworzenie kodu MSIL.

background image

Programowanie Obiektowe

211

Serializacja

Konwersja złożonych hierarchicznych struktur danych do strumieni danych

Deserializacja – operacja odwrotna

Przestrzenie nazw

System.Runtime.Serialization.*

,

System.Xml.Serialization.*

.

Podział zadań: strumienie, obiekty formatujące, obiekty serializowane.

Jawna serializacja:

1

public void SerializeGraph(string file, object root) {

2

Stream stm = new FileStream(file, FileMode.Create);

3

IFormatter fmt = new BinaryFormatter( );

4

fmt.Serialize(stm, root);

5

stm.Flush( );

6

stm.Close( );

7

}

background image

Programowanie Obiektowe

212

Jawna deserializacja:

1

public object DeserializeGraph(string file) {

2

Stream stm = new FileStream(file, FileMode.Open);

3

IFormatter fmt = new SoapFormatter( );

4

object o = fmt.Deserialize(stm);

5

stm.Close( );

6

return o;

7

}

background image

Programowanie Obiektowe

213

Niejawna serializacja

gdy serializujemy obiekt zawierający jako pola inne serializowalne obiekty,

1

[Serializable]

2

public sealed class Person {

3

public string Name;

4

public int Age;

5

}

6

7

[Serializable]

8

public sealed class Team {

9

public string Name;

10

public Person[ ] Players;

11

}

gdy przekazujemy argumenty metodzie wołanej w innej domenie aplikacji,

1

public Team MergeTeams(Team teamOne, Team teamTwo) {...}

w innych przypadkach zdalnego uruchamiania.

background image

Programowanie Obiektowe

214

Atrybut

Serializable

Ustawia odpowiedni bit w meta-danych o typie.

Nie jest dziedziczony – klasy potomne muszą redeklarować atrybut.

Wszystkie składowe muszą być też serializowalne.

Atrybut

NonSerialized

– wyłącza pola z serializacji.

1

[Serializable]

2

public sealed class Person {

3

public string Name;

4

public DateTime DateOfBirth;

5

[NonSerialized] public int Age;

// Can be calculated

6

// Rest of class...

7

}

background image

Programowanie Obiektowe

215

Interfejs

IDeserializationCallback

– pozwala ustawić po

deserializacji pola wyłączone z serializacji

1

[Serializable]

2

public sealed class Person : IDeserializationCallback {

3

public string Name;

4

public DateTime DateOfBirth;

5

[NonSerialized] public int Age;

// Can be calculated

6

public void OnDeserialization(object o) {

7

TimeSpan ts = DateTime.Now - DateOfBirth;

8

Age = ts.Days/365;

// Rough age in years

9

}

10

// Rest of class...

11

}

background image

Programowanie Obiektowe

216

Interfejs

ISerializable

Pozwala na więcej kontroli nad szczegółami serializacji.

Potrzeba implementacji konstruktora deserializacyjnego:

1

[Serializable]

2

public sealed class Team : ISerializable {

3

public string Name;

4

public Person[ ] Players;

5

public void GetObjectData(SerializationInfo si,

6

StreamingContext sc) {

7

si.AddValue(

"IChangedTheFieldName"

, Name);

8

si.AddValue(

"Players"

, Players);

9

}

10

private Team(SerializationInfo si, StreamingContext sc) {

11

Name = si.GetString(

"IChangedTheFieldName"

);

12

Players = (Person[ ])si.GetValue(

"Players"

,

13

typeof(Person[ ]));

14

}

15

}

background image

Programowanie Obiektowe

217

Strumienie

Abstrakcyjna klasa

Stream

i jej pochodne – niskopoziomowy zapis i

odczyt

CanRead

,

CanWrite

,

CanSeek

Read()

,

Write()

– binarny odczyt i zapis

metody

Seek()

,

SetLength()

i własności

Position

,

Length

BeginRead()

,

EndRead()

,

BeginWrite()

,

EndWrite()

operacje asynchroniczne

Flush()

,

Close()

background image

Programowanie Obiektowe

218

Klasy potomne:

Microsoft.JScript.COMCharStream

Microsoft.WindowsMobile.DirectX.GraphicsStream

System.IO.BufferedStream

System.IO.Compression.DeflateStream

System.IO.Compression.GZipStream

System.IO.FileStream

System.IO.MemoryStream

System.IO.UnmanagedMemoryStream

System.Net.Security.AuthenticatedStream

System.Net.Sockets.NetworkStream

System.Security.Cryptography.CryptoStream

background image

Programowanie Obiektowe

219

Klasy usprawniające pisanie i czytanie

BinaryReader

,

BinaryWriter

,

StreamReader

,

StreamWriter

,

Encoding

,

StringReader

,

StringWriter

,

TextReader

,

TextWriter

– abstrakcyjne klasy bazowe dla

StreamXXX

i

StringXXX

.

background image

Programowanie Obiektowe

220

Podstawowe klasy obsługi wejścia/wyjścia

Directory

– metody statyczne

DirectoryInfo

– metody w kontekście obiektu

DriveInfo

– metody obsługi napędu

File

– metody statyczne

FileInfo

– metody w kontekście obiektu

FileSystemInfo

– klasa abstrakcyjna, bazowa dla FileInfo i DirectoryInfo

Path

– obsługa ścieżek (wieloplatformowa)

SerialPort

– obsługa portów szeregowych

File

,

FileInfo

,

DriveInfo

,

Path

,

Directory

,

DirectoryInfo

sealed

background image

Programowanie Obiektowe

221

Podstawowy przykład użycia strumieni:

1

using System.IO;

2

class StreamFun {

3

static void Main() {

4

Stream s = new FileStream(

"foo.txt"

, FileMode.Create);

5

s.WriteByte(67);

6

s.WriteByte(35);

7

s.Close();

8

}

9

}

background image

Programowanie Obiektowe

222

Buforowanie odczytu i zapisu:

1

void Run( )

2

{

3

Stream inStream = File.OpenRead(

"plik"

);

4

Stream outStream = File.OpenWrite(

"plik.kopia"

);

5

BufferedStream bufIn = new BufferedStream(inStream);

6

BufferedStream bufOut = new BufferedStream(outStream);

7

8

byte[] buffer = new Byte[1024];

9

int bytesRead;

10

while ( (bytesRead = bufIn.Read(buffer, 0, 1024)) > 0 )

11

bufOut.Write(buffer, 0, bytesRead);

12

13

bufOut.Flush( );

14

bufIn.Close( );

15

bufOut.Close( );

16

}

background image

Programowanie Obiektowe

223

Bardziej zaawansowany przykład użycia strumieni:

1

using System;

2

using System.IO;

3

using System.Security.Cryptography;

4

class EncoderFun {

5

static void Main() {

6

Stream stm = new FileStream(

"foo.txt"

,

7

FileMode.Open, FileAccess.Read);

8

ICryptoTransform ict = new ToBase64Transform();

9

CryptoStream cs = new CryptoStream(stm,

10

ict, CryptoStreamMode.Read);

11

TextReader tr = new StreamReader(cs);

12

string s = tr.ReadToEnd();

13

Console.WriteLine(s);

14

}

15

}

background image

Programowanie Obiektowe

224

Binarny zapis i odczyt:

1

public class Student {

2

public string Name;

3

public int Age;

4

public double GPA; }

5

void SaveToStream(Stream stm, Student s) {

6

BinaryWriter bw = new BinaryWriter(stm);

7

bw.Write(s.Name);

8

bw.Write(s.Age);

9

bw.Write(s.GPA);

10

bw.Flush();

// Ensure the BinaryWriter buffer is empty

11

}

12

void ReadFromStream(Stream stm, Student s) {

13

BinaryReader br = new BinaryReader(stm);

14

s.Name = br.ReadString();

15

s.Age = br.ReadInt32();

16

s.GPA = br.ReadDouble();

17

}

background image

Programowanie Obiektowe

225

Strumienie tekstowe:

1

void SaveToStream(Stream stm, Student s) {

2

TextWriter tw = new StreamWriter(stm);

3

tw.WriteLine(s.Name);

4

tw.WriteLine(s.Age);

5

tw.WriteLine(s.GPA);

6

tw.Flush();

// Ensure the TextWriter buffer is empty

7

}

8

void ReadFromStream(Stream stm, Student s) {

9

TextReader tr = new StreamReader(stm);

10

s.Name = tr.ReadLine();

11

s.Age = Int32.Parse(tr.ReadLine());

12

s.GPA = Double.Parse(tr.ReadLine());

13

}

background image

Programowanie Obiektowe

226

Łańcuchy znaków jako strumienie:

1

using System;

2

using System.IO;

3

using System.Text;

4

class Test {

5

static void Main() {

6

StringBuilder sb = new StringBuilder();

7

StringWriter sw = new StringWriter(sb);

8

WriteHello(sw);

9

Console.WriteLine(sb);

10

}

11

static void WriteHello(TextWriter tw) {

12

tw.Write(

"Hello, String I/O!"

);

13

}

14

}

background image

Programowanie Obiektowe

227

Asynchroniczne wejście/wyjście:

1

using System

;

2

using System

.

IO

;

3

using System

.

Text

;

4

class AsyncReadFun

{

5

class AsyncReadState

{

6

public Stream stm

;

// Underlying stream

7

public byte

[]

buf

=

new byte

[256];

// Read buffer

8

public StringBuilder sb

=

new StringBuilder

();

// Result buffer

9

public AsyncCallback acb

=

new AsyncCallback

(

ReadCallback

);

10

}

11

static void AReadCallback

(

IAsyncResult iar

) {

12

AsyncReadState ars

= (

AsyncReadState

)

iar

.

AsyncState

;

13

int bytes

=

ars

.

stm

.

EndRead

(

iar

);

// Get count of bytes read

14

if

(

bytes

> 0) {

// Copy read bytes and restart read

15

ars

.

sb

.

Append

(

Encoding

.

ASCII

.

GetString

(

ars

.

buf

, 0,

bytes

));

16

Console

.

WriteLine

(

"Read chunk of {0} bytes"

,

bytes

);

17

ars

.

stm

.

BeginRead

(

ars

.

buf

, 0,

ars

.

buf

.

Length

,

ars

.

acb

,

ars

);

18

}

background image

Programowanie Obiektowe

228

19

}

20

static void Main

(

string

[]

args

) {

21

// Open the stream & start reading

22

Stream s

=

File

.

OpenRead

(

args

[0]);

23

AsyncReadState ars

=

new AsyncReadState

();

24

ars

.

stm

=

s

;

// Save the stream reference

25

IAsyncResult iar

=

s

.

BeginRead

(

ars

.

buf

, 0,

ars

.

buf

.

Length

,

26

ars

.

acb

,

ars

);

27

// Download a file while we’re reading the stream

28

System

.

Net

.

WebClient wc

=

new System

.

Net

.

WebClient

();

29

wc

.

DownloadFile

(

"http://www.oreilly.com"

,

"index.html"

);

30

Console

.

WriteLine

(

"Finished downloading index.html."

);

31

// Wait until the async read is done

32

iar

.

AsyncWaitHandle

.

WaitOne

();

33

Console

.

WriteLine

(

ars

.

sb

);

34

}

35

}

background image

Programowanie Obiektowe

229

Typy ogólne – generics

Idea mniej-więcej ta sama co szablonów w C++: typy sparametryzowane
typami.

Różnice:

Parametrami mogą być tylko typy.

Założenia co do typu parametryzującego muszą być ujawnione w
deklaracji klasy ogólnej.

Typy kompilowane do kodu pośredniego, typy szczegółowe powstają
dopiero w wyniku działania komplatora JIT

Przykład korzystania:

1

Stack<int> stack = new Stack<int>();

2

for (int i=0; i<10; i++)

3

stack.Push(i);

4

for (int i=0; i<10; i++)

5

Console.WriteLine(stack.Pop());

background image

Programowanie Obiektowe

230

Kolekcje

ICollection

Count

,

CopyTo()

.

IEnumerable

GetEnumerator()

.

IEnumerator

Current

,

MoveNext()

,

Reset()

.

foreach

ułatwia używanie enumeratorów.

wersja 2.0 – iteratory,

yield return

oraz

yield break

1

public IEnumerator GetEnumerator() {

2

for (int i = count - 1; i >= 0; --i) {

3

yield return items[i];

4

}

5

}

Przestrzeń nazw

System.Collections.Generic

.

background image

Programowanie Obiektowe

231

Ogólne klasy

Comparer

– klasa bazowa dla imlplementacji

IComparer

.

Dictionary

– słownik (kolekcja par klucz–wartość).

Dictionary.KeyCollection

– Kolekcja kluczy słownika.

Dictionary.ValueCollection

– Kolekcja wartości słownika.

EqualityComparer

– klasa bazowa dla implementacji

IEqualityComparer

.

KeyNotFoundException

– wyjątek dla słowników.

LinkedList

– lista dwukierunkowa.

LinkedListNode

– węzeł listy dwukierunkowej.

List

– lista indeksowana.

Queue

– kolejka.

SortedDictionary

– słownik posortowany.

SortedDictionary.KeyCollection

.

SortedDictionary.ValueCollection

.

SortedList

– kolekcja par klucz-wartość posortowanych przy użyciu

implementacji

IComparer

.

Stack

– stos.

background image

Programowanie Obiektowe

232

Ogólne interfejsy

ICollection<T> : IEnumerable<T>, IEnumerable

Count

,

IsReadOnly

,

Add()

,

Clear()

,

Contains()

,

CopyTo()

,

Remove()

.

IComparer<T>

Compare()

IDictionary<TKey,TValue> :

ICollection<KeyValuePair<TKey,TValue>>,

IEnumerable<KeyValuePair<TKey,TValue>>, IEnumerable

Item[]

,

Keys

,

Values

,

Add()

,

ContainsKey()

,

Remove()

,

TryGetValue()

IEnumerable<T> : IEnumerable

GetEnumerator()

IEnumerator<T> : IDisposable, IEnumerator

Current

,

MoveNext()

,

Reset()

background image

Programowanie Obiektowe

233

IEqualityComparer<T>

Equals()

,

GetHashCode()

IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable

Item[]

,

IndexOf()

,

Insert()

,

RemoveAt()

background image

Programowanie Obiektowe

234

Ogólne struktury

Dictionary.Enumerator

Dictionary.KeyCollection.Enumerator

Dictionary.ValueCollection.Enumerator

KeyValuePair

LinkedList.Enumerator

List.Enumerator

Queue.Enumerator

SortedDictionary.Enumerator

SortedDictionary.KeyCollection.Enumerator

SortedDictionary.ValueCollection.Enumerator

Stack.Enumerator

background image

Programowanie Obiektowe

235

Przykład użycia słownika:

1

Dictionary<string, int> wzrost =

2

new Dictionary<string, int>();

3

wzrost.Add(

"Mariusz"

, 197);

4

wzrost.Add(

"Marcin"

, 211);

5

Console.WriteLine(

"Mariusz ma {0} cm wzrostu, a Marcin {1}"

,

6

wzrost[

"Mariusz"

], wzrost[

"Marcin"

]);

background image

Programowanie Obiektowe

236

Definiowanie klas ogólnych:

1

public class Tablica<T>

2

{

3

T[] tablica;

4

Tablica(int n) {

5

tablica = new T[n];

6

}

7

T this[int i] { return tablica[i]; }

8

...

9

}

background image

Programowanie Obiektowe

237

Założenia co do typów-parametrów:

1

public class Dictionary<K,V>

2

where K: IComparable

3

{

4

public void Add(K key, V value)

5

{

6

...

7

if (key.CompareTo(x) < 0) {...}

8

...

9

}

10

}

background image

Programowanie Obiektowe

238

Metody ogólne

1

public static swap<T>(ref T x, ref T y)

2

{

3

T z = x;

4

x = y;

5

y = z;

6

}

Założenia co do typów-parametrów metod:

1

public static Min<T>(params T[] tab)

2

where T : IComparable<T>

3

{

4

T min = tab[0];

5

for (int i=0; i<tab.Length; i++)

6

if (tab[i] < min)

7

min = tab[i];

8

return min;

9

}

background image

Programowanie Obiektowe

239

Wyjątki

Schemat:

1

try {

2

...

3

}

4

catch (ExceptionA e) {

5

...

6

}

7

catch (ExceptionB e) {

8

...

9

}

10

finally {

11

...

12

}

Musi wystąpić przynajmniej jedna sekcja

catch

lub

finally

.

catch

i

finally

się wzajemnie nie wykluczają jak w C++.

background image

Programowanie Obiektowe

240

Tylko pierwsza pasująca sekcja

catch

jest wykonywana.

Klasy wyjątków muszą dziedziczyć po

System.Exception

.

Klasa

System.Exception

zawiera m.in. własności:

Message

– opis wyjątku,

StackTrace

– stos wywołań,

TargetSite

– metoda, która zgłosiła wyjątek,

Data

– słownik z dodatkowymi informacjami o wyjątku.

Przykład:

1

public class WeightCalculator

2

{

3

public static float CalcBMI

(

float kilos

,

float meters

) {

4

if

(

meters

< 0 ||

meters

> 3)

5

throw new ArgumentException

(

"Impossible Height"

,

"meters"

);

6

if

(

kilos

< 0 ||

kilos

> 1000)

7

throw new ArgumentException

(

"Impossible Weight"

,

"kilos"

);

8

return kilos

/ (

meters

meters

);

9

}

10

}

background image

Programowanie Obiektowe

241

11

class Test

{

12

static void Main

() {

13

TestIt

();

14

}

15

static void TestIt

() {

16

try

{

17

float bmi

=

WeightCalculator

.

CalcBMI

(100, 5);

18

Console

.

WriteLine

(

bmi

);

19

}

20

catch

(

ArgumentException ex

) {

21

Console

.

WriteLine

(

ex

);

22

}

23

finally

{

24

Console

.

WriteLine

(

"Thanks for running the program"

);

25

}

26

Console

.

Read

();

27

}

28

}

background image

Programowanie Obiektowe

242

Tryb niechroniony - unsafe

Metody i bloki niechronione oznacza się słowem kluczowym

unsafe

.

Używanie wskaźników możliwe jest tylko w trybie niechronionym.
Konieczne jest wówczas „przyszpilowanie” obiektu deklaracją

fixed

.

Przykład:

1

unsafe void RedFilter(int[,] bitmap) {

2

const int length = bitmap.Length;

3

fixed (int* b = bitmap) {

4

int* p = b;

5

for(int i = 0; i < length; i++)

6

*p++ &= 0xFF;

7

}

8

}

background image

Programowanie Obiektowe

243

Przykład mnożenia macierzy:

1

public static Macierz operator*(Macierz m1, Macierz m2) {

2

Macierz m3 = new Macierz(m1.LWierszy, m2.LKolumn);

3

unsafe {

4

fixed (double* pocz1 = m1.warto´

sci) {

5

fixed (double* pocz2 = m2.warto´

sci) {

6

fixed (double* pocz3 = m3.warto´

sci) {

7

double *p1 = pocz1,

8

koniec1 = pocz1+m1.LWierszy*m1.LKolumn;

9

while (p1 < koniec1)

10

{

11

...

12

}

13

}

14

}

15

}

16

}

17

}


Wyszukiwarka

Podobne podstrony:
Programowanie obiektowe, wyklad6-czesc1, Dziedziczenie wielobazowe
11 10 2011 programowanie obiektowe wykład
Programowanie obiektowe, wyklad5, Dziedziczenie
Programowanie obiektowe, wyklad8, Kolekcje
Programowanie Obiektowe wykłady
wyklad5.cpp, JAVA jest językiem programowania obiektowego
Wyklad 3-4, uwm wnt Mecha, SM 5, Programowanie obiektowe i strukturalne, Wykłady
Wyklad 5-6, uwm wnt Mecha, SM 5, Programowanie obiektowe i strukturalne, Wykłady
Cwiczenie 1, uwm wnt Mecha, SM 5, Programowanie obiektowe i strukturalne, Wykłady
Wykład z programowania obiektowego, Informatyka, Semsetr 2, Programowanie obiektowe
Cwiczenie 4 Rozwiazania, uwm wnt Mecha, SM 5, Programowanie obiektowe i strukturalne, Wykłady
Wyklad 9-10, uwm wnt Mecha, SM 5, Programowanie obiektowe i strukturalne, Wykłady
Wyklad 13-14, uwm wnt Mecha, SM 5, Programowanie obiektowe i strukturalne, Wykłady
Programowanie obiektowe(ćw) 1
Zadanie projekt przychodnia lekarska, Programowanie obiektowe
Programowanie obiektowe w PHP4 i PHP5 11 2005
Programowanie Obiektowe ZadTest Nieznany
13 Bazy danych obiektowość wykładid 14617

więcej podobnych podstron