programowanie C java

background image

Programowanie obiektowe

Wojciech Kordecki

Zakład Pomiarowej i Medycznej Aparatury Elektronicznej

Wydział Podstawowych Problemów Techniki

Politechnika Wrocławska

Wrocław 2003

background image

1

Wstęp

Czym będziemy się zajmować?

1. Mechanizmy występujące w C++.

• Dynamiczne tworzenie obiektów, konstruktory i destruktory.
• Wzorce klas i ich zastosowania.
• Dziedziczenie wielokrotne.
• Funkcje i klasy zaprzyjaźnione.
• Operacje wejścia – wyjścia
• Wyjątki

2. Elementy Javy.

2

background image

3. Model klient – serwer.

Oprócz tego:

• Dygresje o programowaniu obiektowym w Turbo Pascalu.

• Trochę o programach Delphi i C++ Builder.

3

background image

Literatura polecana

[1] B. Stroustrup, Język C++. WNT, Warszawa 1994 (i wyd. nast.).

[2] J. Grębosz, Symfonia C++. Oficyna Kallimach, Kraków 1999.

[3] J. Grębosz, Pasja C++. Oficyna Kallimach, Kraków 1999.

[4] S. B. Lippman, J. Lajoie, Podstawy języka C++, WNT, Warszawa

2001.

[5] S. B. Lippman, Model obiektu w C++. WNT, Warszawa 1999.

[6] A. Struzińska-Walczak, K. Walczak, Nauka programowania w języku

C++. Wydawnictwo W&W, Warszawa 1998.

4

background image

[7] J. Liberty, C++ Księga eksperta. Helion, Gliwice 1999.

[8] K. Jamsa, Wygraj z C++. Mikom, Warszawa 1996.

[9] J. Kisilewicz, Język C++. Programowanie obiektowe. Oficyna

Wydawnicza P. Wr. Wrocław 2002.

[10] B. Boone, Java dla programistów w C i C++. WNT, Warszawa

1998.

[11] S. Holzner, JAVA 2, szybkie wprowadzenie. Help, 2002.

[12] K. Walczak, Java. Wydawnictwo W&W, Warszawa 2002.

5

background image

2

Klasy w C++ i Pascalu

2.1

Obiekty w C++ i Pascalu - początki

W C++ – struktury, w Pascalu – rekordy, grupują dane różnych typów.
Przykład. Liczby zespolone w Pascalu – dodawanie i mnożenie.

type

complex=record

x:double;

y:double;

end;

var

z,z1,z2:complex;

6

background image

procedure plus(z1,z2:complex;var z:complex);

begin

z.x:=z1.x+z2.x;

z.y:=z1.y+z2.y;

end;

procedure times(z1,z2:complex;var z:complex);

begin

z.x:=z1.x*z2.x-z1.y*z2.y;

z.y:=z1.x*z2.y+z2.x*z1.y;

end;

7

background image

Przykład. Liczby zespolone w C++ – dodawanie i mnożenie.

#include "complex.h"

struct complex z1,z2,z;

struct complex plus(struct complex z1,struct complex z2)

{

struct complex z;

z.x=z1.x+z2.x;

z.y=z1.y+z2.y;

return(z);

}

8

background image

struct complex times(struct complex z1,struct complex z2)

{

struct complex z;

z.x:=z1.x*z2.x-z1.y*z2.y;

z.y:=z1.x*z2.y+z2.x*z1.y;

return(z);

}

9

background image

Plik nagłówkowy complex.h

struct complex

{

double x;

double y;

};

struct complex plus(struct complex z1,struct complex z2);

struct complex times(struct complex z1,struct complex z2);

10

background image

W tych programach dane i operacje na nich są luźno związane. Trochę
lepiej wygląda to, gdy operacje są już na danych określonych typów.

type {Turbo Pascal}

complex=object

x:double;

y:double;

end;

complex_operation=object(complex)

procedure plus(z1,z2:complex;var z:complex);

procedure times(z1,z2:complex;var z:complex);

end;

11

background image

procedure

complex_operation.plus(z1,z2:complex;var z:complex);

begin

z.x:=z1.x+z2.x;

z.y:=z1.y+z2.y;

end;

procedure

complex_operation.times(z1,z2:complex;var z:complex);

begin

z.x:=z1.x*z2.x-z1.y*z2.y;

z.y:=z1.x*z2.y+z2.x*z1.y;

end;

12

background image

Odpowiedni fragment programu może być taki:

var

z,z1,z2,

o:complex_operation;

begin

write(’x1=’);read(z1.x);

write(’y1=’);read(z1.y);

write(’x2=’);read(z2.x);

write(’y2=’);read(z2.y);

o.plus(z1,z2,z);writeln(z.x:0:4,’+i’,z.y:0:4);

o.times(z1,z2,z);writeln(z.x:0:4,’+i’,z.y:0:4);

end.

13

background image

Można obiekty określać „na raty”.

type

complex=object

x:double;

y:double;

end;

plus_operation=object(complex)

procedure plus(z1,z2:complex;var z:complex);

end;

complex_operation=object(plus_operation)

procedure times(z1,z2:complex;var z:complex);

end;

14

background image

procedure

plus_operation.plus(z1,z2:complex;var z:complex);

begin

z.x:=z1.x+z2.x;

z.y:=z1.y+z2.y;

end;

procedure

complex_operation.times(z1,z2:complex;var z:complex);

begin

z.x:=z1.x*z2.x-z1.y*z2.y;

z.y:=z1.x*z2.y+z2.x*z1.y;

end;

15

background image

Inne pytanie. Dlaczego musimy pisać plus(z1,z2,z) zamiast po prostu
z=z1+z2, tak jak piszemy z = z

1

+ z

2

? Odpowiedź później. W C++ na

szczęście nie musimy, ale w Pascalu i Javie tak.
Przykład. Podobnie w C++, ale teraz będą klasy. Zakładamy (dla
uproszczenia), że już wiadomo, co to jest complex.

class complex_operation

{

struct complex plus(struct complex z1,struct complex z2);

struct complex times(struct complex z1,struct complex z2);

}

16

background image

Funkcje plus oraz times definiujemy osobno.

complex_operation::

struct complex plus(struct complex z1,struct complex z2)

{

struct complex z;

z.x:=z1.x*z2.x-z1.y*z2.y;

z.y:=z1.x*z2.y+z2.x*z1.y;

return(z);

}

17

background image

Można je też definiować wewnątrz klasy.

class complex_operation

{

complex_operation(); // konstruktor

~complex_operation(); // destruktor

struct complex plus(struct complex z1,struct complex z2)

{

struct complex z;

z.x:=z1.x*z2.x-z1.y*z2.y;

z.y:=z1.x*z2.y+z2.x*z1.y;

return(z);

}

18

background image

struct complex times(struct complex z1,struct complex z2);

}

2.2

Enkapsulacja

Etykiety:

private:

public:

protected:
Mogą być umieszczane w dowolnej kolejności.

19

background image

Schemat klasy:

class nazwa_klasy

{

// składniki, domyślnie private

}

Składnikami klasy mogą być zmienne i funkcje czyli metody. W klasie
może być zawarta tylko deklaracja metody albo również jej definicja.
Definicja umieszczona na zewnątrz klasy poprzedzona jest nazwą klasy i
operatorem zakresu.

20

background image

Przykład.

#include <iostream.h>

class moja_klasa

{

// domyślnie private

int n;

public:

void ustal_n(int k){n=k;}

int podaj_n(){return n;}

void zmien_n(int k){n+=k;}

double f(int k);

21

background image

};

double moja_klasa::f(int k){return n*n/(3.14*k);}

int main()

{

moja_klasa a,b;

a.ustal_n(3);

b.ustal_n(4);

cout << a.podaj_n() << endl;

cout << b.podaj_n() << endl;

cout << a.f(2);

22

background image

return 0;

}

Do składników klasy (publicznych) mamy dostęp:

• obiekt.składnik

• wskaźnik->składnik

23

background image

Składowe statyczne:

static int n
Teraz n jest wspólne dla wszystkich obiektów. Do składników
statycznych klasy mamy dostęp:

• klasa::składnik

• obiekt.składnik

• wskaźnik->składnik

24

background image

2.3

Konstrukcja, destrukcja i przyjaźń

Klasa:

class list:public element{

int n;

item *p;

public:

list(int size); // (1) konstruktor

~list; // (2) destruktor

void put(float x); // (3)

float first();

float last()

float get(int n);

25

background image

void delete(int n);

insert(int n,int position);

friend int length(list &); // (4)

}

26

background image

Klasa element definiuje element item listy postaci
[wartość x, wskaźnik do następnego x] oraz definiuje funkcję

NewElement tworzącą element i zwracającą wskaźnik do niego.

(1) Konstruktor – funkcja o tej samej nazwie co klasa, bez określenia

typu! Jest wykonywana automatycznie przy deklaracji obiektu. W
tym przykładzie tworzy listę pustą, tzn. wskaźnik na nic nie
pokazuje i ustala n = 0.

(2) Destruktor – funkcja wykonywana przy likwidacji obiektu.

(3) Metoda put(float x) tworzy nowy element i dopisuje go na

koniec listy. Dalsze metody podają pierwszy, ostatni, n-ty element
listy, usuwają n-ty element, wstawiają element na wiejsce n-te.

27

background image

(4) Metoda zaprzyjaźniona – ma dostęp do prywatnych składników

klasy.

28

background image

3

Dziedziczenie

3.1

Podstawowe zasady

Dziedziczenie:

class przodek

{

private:

int n;

protected:

int bla_bla(int);

public:

void bla_bla_bla(int);

29

background image

przodek(int);

};

class dziedzic : public przodek;

{

public:

bla_bla_bla_bla(int);

dziedzic(int);

};

Klasa dziedzic zachowuje się tak jak

30

background image

class przodek_i_dziedzic

{

private:

int n;

public:

int bla_bla(int);

void bla_bla_bla(int);

void bla_bla_bla_bla(int);

};

3.2

Więcej o konstruktorach

Nie wszystko się dziedziczy.

31

background image

Nie dziedziczy się konstruktorów, destruktorów i operatora przypisania
(operator=).
Klasa pochodna uruchamia najpierw konstruktor klasy podstawowej z
odpowiednimi parametrami.

dziedzic::dziedzic(int nn):przodek(nn)

{

};

Używane często funkcje new oraz delete w stosunku do tablic:

int *t;

new t[10];

32

background image

// ?????

delete [] t;

albo

int *t;

int n=10;

new t[n];

// ?????

delete [] t;

Tablice wielowymiarowe (tutaj dwuwymiarowe):

int *t;

new t[10][10];

33

background image

// ?????

delete [] t;

ale nie (niestety)

int *t;

int n=10;

new t[n][n];

// ?????

delete [] t;

ale

int *t;

int n=10;

34

background image

new t[n][10];

// ?????

delete [] t;

albo

int *t;

int n=10;

new t[n*n];

// ?????

delete [] t;

wtedy musimy je używać w postaci t[n*i+j].

35

background image

3.3

Przykład

#include <iostream.h>

int fact(int);

class cpermutation;

class permutation;

//////////////////////////////////////////////

int fact(int n) // silnia, czyli n!

36

background image

{

int m=1;

int k;

for(k=1;k<=n;k++) m*=k;

return m;

}

//////////////////////////////////////////////

37

background image

class cpermutation

{

protected:

int n; // dlugosc permutacji

int m; // liczba wszystkich permutacji: n! - to na pozniej

int na; // aktualna liczba permutacji

int *perm; // tablica permutacji, permutacja=wektor

public:

cpermutation(int);

~cpermutation(){delete [] perm;};

void perm_out(void);

};

38

background image

cpermutation::cpermutation(int nn)

{

int i,j;

n=nn;

m=fact(nn);

na=nn;

perm=new int[m*n];

for(i=0;i<na;i++){for(j=0;j<n;j++){perm[n*i+j]=(i+j)%n; //

}};

};

39

background image

void cpermutation::perm_out(void)

{

int i,j;

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

{

for(j=0;j<n;j++)

{

cout << perm[n*i+j] << " ";

};

cout << endl;

};

};

40

background image

class permutation:public cpermutation

{

public:

permutation(int);

};

permutation::permutation(int nn):cpermutation(nn)

{

};

41

background image

int main()

{

int i,j;

cpermutation p1(3);

permutation p2(3);

p1.perm_out();

cout << "Uwaga! Bzdet!" << endl;

p2.perm_out(); // tu bzdury, bo konstruktor nie konstruuje

return 0;

};

42

background image

0 1 2

1 2 0

2 0 1

Uwaga! Bzdet!

0 1 2

1 2 0

2 0 1

0 0 0

0 0 0

0 0 0

43

background image

3.4

Kolejność wywoływania konstruktorów

Konstruktory uruchamiane są wg hierarchii, tzn. najpierw klasa
podstawowa, potem jej pochodna itd.
Na liście inicjalizacyjnej można pominąć wywołanie konstruktora
bezpośredniej klasy podstawowej tylko wtedy gdy:

• klasa podstawowa nie ma żadnego konstruktora,

• ma konstruktory, a wśród nich jest domniemany.

44

background image

#include <iostream.h>

#include <stdlib.h> // m.in. funkcje atoi, atof

class nn

{

protected:

int n;

public:

nn(int m) : n(m)

{

cout << n << endl;

}

};

45

background image

int main(int argc, char *argv[])

{

if(argc!=2){return 1;};

int k;

k=atoi(argv[1]);

nn x(k);

return 0;

}

46

background image

#include <iostream.h>

#include <stdlib.h>

int main(int argc, char *argv[])

{

if(argc!=2){return 1;};

int k;

k=atoi(argv[1]);

int n;

n(k);

// NIE!

return 0;

}

47

background image

Przykład.
Hierarchia klas

nn

1

nn

2

nn

3

→ nn

4

[nn

1

]

→ nn

5

[nn

4

]

przodek

daleki potomek

kl

1

[kl

2

] oznacza, że klasa kl

1

zawiera klasę kl

2

.

Deklarujemy obiekty klas nn

4

oraz nn

5

.

#include <iostream.h>

#include <stdlib.h>

48

background image

class nn1

{

protected:

int n1;

public:

nn1(int m):n1(m)

{cout << "nn1 " << n1 << endl;}

~nn1()

{cout << "dd1 " << n1 << endl;}

};

49

background image

class nn2

{

int n2;

public:

nn2(int m):n2(m)

{cout << "nn2 " << n2 << endl;}

~nn2()

{cout << "dd1 " << n2 << endl;}

};

50

background image

class nn3

{

public:

nn3()

{cout << "nn3 "

<< endl;}

~nn3()

{cout << "dd3 "

<< endl;}

};

51

background image

class nn4:public nn3

{

protected:

nn1 n4;

public:

nn4(int m) :n4(m),nn3()

{cout << "nn4 "

<< m << endl;}

~nn4()

{cout << "dd4 "

<< endl;}

};

52

background image

class nn5:nn4

{

protected:

nn2 m5;

public:

nn5(int m):m5(m),nn4(m)

{cout << "nn5 " << endl;}

~nn5()

{cout << "dd5 " << endl;}

};

53

background image

int main(int argc, char *argv[]) // program multi

{

if(argc!=3){return 1;};

int i;

int j;

i=atoi(argv[1]);

j=atoi(argv[2]);

nn4 x(i);

nn5 y(j);

return 0;

}

54

background image

Program multi 1 2

Wywoływanie konstruktorów

nn3

nn1 1

nn4 1

nn3

nn1 2

nn4 2

nn2 2

nn5

55

background image

Wywoływanie destruktorów

dd5

dd1 2

dd4

dd1 2

dd3

dd4

dd1 1

dd3

56

background image

3.5

Dziedziczenie wielokrotne

Klasa może wywodzić się więcej niż od jednej klasy.

mama
tata



→ dziecko

Nie wystarczy tylko

class mama;

Definicja klasy umieszczonej na liście pochodzenia musi być znana
kompilatorowi – nie wystarczy deklaracja zapowiadająca.

57

background image

class mama{

// ...

};

class tata{

// ...

};

class dziecko: public mama, public tata

{

// ...

};

58

background image

#include <iostream.h>

class mama

{

protected:

int wm;

public:

mama(int m) : wm(m)

{

cout << "Wiek mamy " << wm << endl;

}

};

59

background image

class tata

{

protected:

int wt;

public:

tata(int m) : wt(m)

{

cout << "Wiek taty " << wt << endl;

}

};

60

background image

class dziecko : public mama, public tata

{

public:

dziecko() : mama(20), tata(21)

{cout << "Rodzice Zosi w wieku:\n";}

void wiek_rodzicow(){

cout << "Mama " << wm<<" lat,\tTata "

<< wt << " lat.\n";

}

};

61

background image

main()

{

dziecko Zosia;

Zosia.wiek_rodzicow();

}

Rezultat działania programu

Wiek mamy 20

Wiek taty 21

Rodzice Zosi w wieku:

Mama 20 lat,Tata 21 lat.

62

background image

#include <iostream.h>

class mama

{

protected:

int wiek;

public:

mama(int m) : wiek(m)

{

cout << "Wiek mamy " << wiek << endl;

}

};

63

background image

class tata

{

protected:

int wiek;

public:

tata(int m) : wiek(m)

{

cout << "Wiek taty " << wiek << endl;

}

};

64

background image

class dziecko : public mama, public tata

{

public:

dziecko() : mama(20), tata(21)

{cout << "Rodzice Zosi w wieku:\n"; }

void wiek_rodzicow()

{

cout << "Mama " << wiek<<" lat,\tTata "

<< wiek << " lat.\n";

}

};

65

background image

main()

{

dziecko Zosia;

Zosia.wiek_rodzicow();

}

Nie wiadomo czyj jest wiek.

66

background image

Borland C++ 5.5 for Win32 Copyright (c) 1993, 2000 Borland

mtd1.cpp:

Error E2014 mtd1.cpp 35: Member is ambiguous:

’mama::wiek’ and ’tata::wiek’

in function dziecko::wiek_rodzicow()

Error E2014 mtd1.cpp 36: Member is ambiguous:

’mama::wiek’ and ’tata::wiek’

in function dziecko::wiek_rodzicow()

*** 2 errors in Compile ***

67

background image

Uniknięcie wieloznaczności:

void wiek_rodzicow()

{

cout << "Mama " << mama::wiek<<" lat,\tTata "

<< tata::wiek << " lat.\n";

}

68

background image

4

C++ a Java

4.1

Podstawy

Java – język czysto obiektowy,

• nie ma zmiennych i funkcji globalnych,

• są tylko klasy,

• nie ma wskaźników – nie ma obawy o przekroczenie zakresu tablic,

• system sam zwalnia pamięć – nie ma destruktorów,

• wielowątkowość,

• obsługa wyjątków,

69

background image

• kompilacja do kodu pośredniego,

• aplety (ang. applets) – programiki w przeglądarkach WWW,

• wykonanie niezależne od sprzętu – JVM.

Tekst źródłowy z rozszerzeniem java.
Tekst skompilowany z rozszerzeniem class.

70

background image

C

C++

Java

Dostęp do
pamięci

Wskaźniki,
adresy

Wskaźniki,
adresy,
obiekty

Obiekty

Grupowanie
danych

Struktury

Struktury,
klasy

Klasy

Sposób
definiowania

Funkcje

Funkcje,
metody

Metody

71

background image

4.2

Proste programy w C++ i Javie

Przykłady z książki [

10

].

Program w C++ zapisany w pliku HelloWorld.cpp.

#include <iostream.h>

main()

{

cout << "Hello World" << endl!;

}

Po skompilowaniu i wykonaniu da efekt:

Hello World!
Program w Javie zapisany w pliku HelloWorld.java.

72

background image

class HelloWorld{

static public void main(String args[])

{

System.out.println("Hello World!");

}

}

Po skompilowaniu

javac HelloWorld.java
i wywołaniu

java HelloWorld
da efekt (ten sam co program w C++):

Hello World!

73

background image

Program w C++

#include <iostream.h>

class Astronaut

{

int earthWeight;

public:

Astronaut(int wt)

{

earthWeight=wt;

}

74

background image

double moonWeight()

{

return earthWeight*0.166;

}

};

main()

{

int weight;

cout << "Ile wazysz na ziemi?" << endl;

cin >> weight;

Astronaut student(weight);

75

background image

cout << "na ksiezycu wazysz "

<< student.moonWeight() << endl;

}

Po skompilowaniu i wykonaniu otrzymujemy (po podaniu własnej wagi
72):

Ile wazysz na Ziemi?

72

Na ksiezycu wazysz 11.952

76

background image

Program zapisany w pliku PlanetaryScale0.java

class Astronaut

{

Double earthWeight;

Astronaut(double weight)

{

earthWeight=new Double(weight);

}

public double moonWeight()

{

77

background image

return earthWeight.doubleValue() * .166;

}

}

class PlanetaryScale

{

Astronaut armstrong;

public static void main(String args[])

{

char c;

double earthWeight;

78

background image

StringBuffer strng=new StringBuffer();

double moonWeight;

Astronaut armstrong;

System.out.println("Ile wazysz na Ziemi?");

try

{

while((c=(char) System.in.read())!=’\n’)

strng.append(c);

earthWeight=

Double.valueOf(strng.toString()).doubleValue();

79

background image

} catch(java.io.IOException e)

{

earthWeight=0.0;

}

armstrong=new Astronaut(earthWeight);

System.out.println("Na ksiezycu wazysz "+

armstrong.moonWeight());

}

}

80

background image

Po skompilowaniu

javac PlanetaryScale0.java
i wywołaniu java PlanetaryScale
otrzymujemy (po podaniu własnej wagi 72):

Ile wazysz na Ziemi?

72

Na ksiezycu wazysz 11.952

81

background image

4.3

Typy danych i operatory

Dwa typy danych – proste i referencyjne. Nie ma wskaźników, typy
złożone przekazywane są przez referencje.
Wszystkie typy proste są ze znakiem.
Trzy typy referencyjne: klasa, interfejs i tablica.

82

background image

Typy proste.

Typ

Rozmiar

byte

1 bajt (liczba całkowita ze znakiem)

boolean 1 bajt (wartości true i false)

char

2 bajty Unicode

short

2 bajty

int

4 bajty

long

8 bajtów

float

4 bajty

double

8 bajtów

83

background image

Typy referencyjne.

String str=new String();

System.out.println("str ma "+str.length()+" znaków.");

W C++ operator new zwracał wskaźnik do obiektu. W Javie operator
ten zawiera referencję do obiektu – nie ma operatora delete, Java sama
zlikwiduje obiekt, do którego nie referencji.
Nie ma operatorów przeciążonych, jedynie + służy również do
konkatenacji (sklejania) łańcuchów.
Dodatkowe (w porównaniu z C++) operatory: >>> przesuwa bity
zmiennej całkowitej w prawo, po lewej stronie wstawiane są zera.
Przesunięcie z przypisaniem >>>=.

84

background image

Przykład.

n = n >>> 1

n >>>= 1
W obu przypadkach n jest przesunięte o jeden bit w prawo.

85

background image

4.4

Klasy

Nie ma średnika po klamrze kończącej klasę.
Kwalifikatory dostępu przed każdą składową.

class myClass

{

public myClass(){/* ... */}

public int n;

protected int f1(){return 1;}

private boolean f2(){return true;}

private double x;

// ... itd.

}

86

background image

Funkcje składowe są zawsze definiowane w deklaracjach klas, nie oznacza
to że są inline.
Parametry typów prostych są przekazywane przez wartość – funkcja
operuje na kopii parametru. Typy obiektowe są przekazywane przez
referencję.
Nie łańcuchów takich jak w C, jest klasa String. Obiekt typu String
jest niezmienny, nie można modyfikować jego zawartości. Utowrzenie
obiektu:

String str="To jest łańcuch";
Długość tego łańcucha jest podawana przez funkcję składową length().
Tablice są klasami – nie można określić rozmiaru tablicy przy deklaracji.
Trzeba użyć new. Nawiasy [] po lewej lub prawej stronie.

87

background image

Przykłady.

int array1[];

int [] array2;

array1=new int[10];

for(int i=0;i<array1.length;i++)array1[i]=i;

Nie można wpisywać danych poza zakresem tablicy. Linia

array1[12]=1;
spowoduje komunikat diagnostyczny:

java.lang.ArrayIndexOutOfBoundsException

88

background image

Każda klasa po czymś dziedziczy. Wszystkie klasy dziedziczą po klasie

Object. Jeśli jawnie nie określi się, po jakiej klasie się dziedziczy, to
dziedziczy się po Object. Zamiast dwukropka jak w C++ używa się
słowa kluczowego extends.
Nie ma dziedziczenia wielokrotnego, można jednak używać interfejsów,
będących odpowiednikami klas abstrakcyjnych – nie mogą one zawierać
definicji składowych.
Interfejsy się implementuje, a nie dziedziczy.

89

background image

Przykład.

public class aaa // domyślnie dziedziczy po Object

{

public void f(String text){/* ... */}

// ...

}

public class bbb extends aaa

{

public void g(){/* ... */}

// ...

}

90

background image

public class ccc extends bbb

{

ccc(){/* ... */}

// ...

}

91

background image

Przykład.

interface aaa

{

public void f(String text);

// ...

}

interface bbb

{

public void g();

// ...

}

92

background image

public class ccc implements aaa,bbb

{

ccc(){/* ... */}

public void f(String text){/* ... */}

public void g(){/* ... */}

// ...

}

Klasy abstrakcyjne nie mogą służyć do deklaracji obiektów, mogą mieć
jednak definicje, jeżeli nie mają, to są poprzedzone słowem abstract.

93

background image

abstract class aaa

{

public void bbb(){/* ... */}

abstract void ccc();

public final int ddd=500; // stała

}

class xxx extends aaa

{

public int eee=50;

public void ccc(){/* ... */}

}

94

background image

Można oczywście przedefiniować składowe

class xxx extends aaa

{

public void bbb(){/* coś innego niż poprzednio */}

public int eee=50;

public void ccc(){/* ... */}

}

95

background image

5

Przeciążanie funkcji i operatorów

5.1

Przeciążanie nazw funkcji

Przeciążanie = przeładowanie = overloading:
więcej niż jedna funkcja o tej samej nazwie w tym samy zakresie
ważności. O tym, którą funkcję wybierze kompilator, decydują typy
argumentów.
Przykład. Potęga liczby dodatniej całkowita lub rzeczywista. Potęga
całkowita: x

n

= x

m+k

, gdzie m = n/2, k = n%2.

#include <iostream.h>

#include <math.h>

96

background image

float power(float x,unsigned int n);

float power(float x,unsigned float y);

float power(float x,int n)

{

switch(n)

{

case 0: return 0;

case 1: return x;

case 2: return x*x;

default:

{

97

background image

float t;

unsigned int i,j;

i=n>>1;

j=n&&1;

return power(x,j)*(t=power(x,i))*t;

}

}

}

98

background image

float power(float x,float y)

{

return exp(y*log(x));

}

main()

{

unsigned int n=5;

float y=5.01;

cout << power(2,n) << endl;

cout << power(2,y) << endl;

}

99

background image

5.2

Przeciążanie operatorów

#include <iostream.h>

class complex;

class complex

{

float re,im;

public:

complex(float r, float i){re=r;im=i;};

complex(float r){re=r;im=0;};

complex(){re=0;im=0;};

100

background image

friend complex operator+(complex, complex);

friend complex complex_out(complex a)

{

cout << a.re << "+i" << a.im << endl;

};

};

complex operator+(complex a, complex b)

{

return complex(a.re+b.re,a.im+b.im);

};

101

background image

int main()

{

complex a(2,2);

complex b(1);

complex c;

c=a+b;

complex_out(c);

return 0;

}

Uwaga. Nie można definiować nowych operatorów. Nie wszystkie
operatory można przeciążać.

102

background image

6

Operacje wejścia/wyjścia

6.1

Strumień

Biblioteki obsługujące operacje wejścia/wyjścia:

iostream.h – jakiekolwiek korzystanie,

fstream.h – operacje we/wy na plikach zewnętrznych,

strstream.h – operacje we/wy na tablicach.

Uwaga. W Borland C++ wystarczy włączyć fstream, gdyż ten sam
włącza iostream

103

background image

Przeciążamy operatory << i >>. Przykłady na klasie complex.
Realizacja przez globalne funkcje operatorowe realizujące przeciążenia <<
oraz >> dla klasy complex.

#include <iostream.h>

class complex

{

public:

float re,im;

complex(float r, float i){re=r;im=i;};

complex(float r){re=r;im=0;};

complex(){re=0;im=0;};

104

background image

friend complex operator+(complex a, complex b)

{

return complex(a.re+b.re,a.im+b.im);

};

};

ostream& operator<<(ostream& strumien_wyj, complex z)

{

strumien_wyj << z.re << "+i" << z.im;

return strumien_wyj ;

}

105

background image

istream& operator>>(istream& strumien_wej, complex &z)

{

strumien_wej >> z.re >> z.im;

return strumien_wej ;

}

main()

{

complex a(2,2);

complex b;

cout << "Podaj b" << endl;

cin >> b;

106

background image

cout << a+b << " jest to liczba zespolona" << endl;

}

107

background image

Realizacja przez funkcje zaprzyjaźnione realizujące przeciążenia << oraz
>> dla klasy complex.

#include <iostream.h>

class complex

{

float re,im;

public:

complex(float r, float i){re=r;im=i;};

complex(float r){re=r;im=0;};

complex(){re=0;im=0;};

108

background image

friend

complex operator+(complex a, complex b)

{

return complex(a.re+b.re,a.im+b.im);

};

friend

ostream& operator<<(ostream& strumien_wyj, complex z)

{

strumien_wyj << z.re << "+i" << z.im;

return strumien_wyj ;

}

109

background image

friend

istream& operator>>(istream& strumien_wej, complex &z)

{

strumien_wej >> z.re >> z.im;

return strumien_wej ;

}

};

110

background image

main()

{

complex a(2,2);

complex b;

cout << "Podaj b" << endl;

cin >> b;

cout << a+b << " jest to liczba zespolona" << endl;

}

111

background image

Wersja „symetryczna”

#include <iostream.h>

class complex

{

float re,im;

public:

complex(float r, float i){re=r;im=i;};

complex(float r){re=r;im=0;};

complex(){re=0;im=0;};

friend

complex operator+(complex a, complex b)

112

background image

{

return complex(a.re+b.re,a.im+b.im);

};

friend

ostream& operator<<(ostream& strumien_wyj, complex z)

{

strumien_wyj << z.re << "+i" << z.im;

return strumien_wyj ;

}

friend

istream& operator>>(istream& strumien_wej, complex &z)

113

background image

{

char a,b;

strumien_wej >> z.re >> a >> b

>> z.im;

return strumien_wej ;

}

};

114

background image

main()

{

complex a(2,2);

complex b;

cout << "Podaj b" << endl;

cin >> b;

cout << a+b << " jest to liczba zespolona" << endl;

}

115

background image

6.2

Sterowanie formatem

Klasa ios, podstawowa dla istream i ostream zawiera publiczny typ
wyliczeniowy

public:

enum{

skipws=0x0001,

left=0x0002,

right=0x0004,

internal=0x0008,

dec=0x0010,

oct=0x0020,

hex=0x0040,

116

background image

showbase=0x0080,

showpoint=0x0100,

uppercase=0x0200,

showpos=0x0400,

scientific=0x0800,

fixed=0x1000,

unitbuf=0x2000,

stdio=0x4000

};

Użycie: ios::left itd.

117

background image

Funkcje zmieniające flagi i reguły formatowania:

• setf ustawia flagi,

• unsetf kasuje flagi,

np. cout.setf(ios::hex), cin.unsetf(ios::hex).
Przykład skopiowany z książki Symfonia C++.

#include <iostream.h>

main()

{

float x = 1175 ;

118

background image

long stare_flagi ;

cout << x << endl;

cout <<"Zapamietanie flag formatowania\n" ;

stare_flagi = cout.flags();

cout.setf(ios::showpoint) ;

cout << x << endl ;

cout.setf(ios::scientific, ios::floatfield);

cout << x << endl ;

119

background image

cout.setf(ios::uppercase);

cout << x << endl ;

cout.unsetf(ios::showpoint) ;

cout << x << endl ;

cout <<"Powrót do starego sposobu formatowania\n" ;

cout.flags(stare_flagi);

cout << x << endl ;

}

120

background image

Wykonanie programu daje w efekcie

1175

Zapamietanie flag formatowania

1175.00

1.175000e+03

1.175000E+03

1.175000E+03

Powrot do starego sposobu formatowania

1175

121

background image

Inne funkcje klasy ios to

• int width(int)

• int width()

• int precision(int)

• int precision()

• int fill(int)

• int fill()

• char fill(char)

• char fill()

122

background image

6.3

Manipulatory

Wartości wstawiane do strumienia, aby wywołać określony efekt: hex,
dec, oct, flush, endl, ends, ws.
np.

int i=30;

cout << i << " " << hex << i;

da w efekcie 30 1e. Manipulatory z parametrami, to

• setw(int) – ustawia szerokość, tak jak funkcja width,

• setfill(int) – podobnie,

• setprecision(int),

123

background image

• setiosflags(long) – odpowiada setf,

• resetiosflags(long) – odpowiada unsetf.

124

background image

6.4

Pliki

Klasy zapewniające możliwość zapisu do pliku lub odczytu:

• ofstream – zapis do pliku

• ifstream – odczyt z pliku

• fstream – zapis i odczyt

Wystarczy włączyć fstream.

125

background image

Kolejność postępowania.

1. Zdefiniowanie obiektu klasy ofstream, ifstream lub fstream.

2. Określenie konkretnego pliku, który kontaktuje się ze strumieniem.

3. Przeprowadzanie operacji we/wy.

4. Zlikwidowanie strumienia.

Otwieranie strumienia – open.
void open(char* name, int mode=xxx, int

prot=filebuf::openprot);
Trzeci argument określa, kto może z tego pliku korzystać – jest zależne
od systemu (np. UNIX).
Tryby otwarcia określone jako typ enum w klasie ios.

126

background image

• in – do czytania

• out – do pisania

• ate – ustawienie się na końcu pliku

• app – do dopisywania

• trunc – otwarcie z ew. skasowaniem jeśli istnieje

• nocreate – otwarcie jeśli istnieje

• noreplace – otwarcie jeśli istnieje

• binary – tryb binarny (domyślny tekstowy), nie zawsze istnieje

Tryby mogą być OR-owane operatorem binarnym

|.

127

background image

#include <fstream.h>

#include <string.h>

#include <stdlib.h>

inline double rnd()

{

return double(rand())/RAND_MAX; // Borland C++

}

int main(int argc, char *argv[])

{

if(argc!=2){return 1;};

128

background image

int n;

n=atoi(argv[1]);

randomize();

//Borland C++

// srandom(1111); //GCC (Linux, Solaris) 1111 - przykładowe

ofstream frnd; //definicja obiektu

frnd.open(argv[2]

,ios::noreplace

);

//otwarcie

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

frnd << rnd() << endl;

//operacje

frnd.close();

//zamknięcie.

129

background image

return 0;

}

Konwersje w trybie tekstowym: przy zapisie do pliku znak ’\n’ jest
zamieniany na parę ’\r’ i ’\n’. Przy odczycie – odwrotnie. W
trybie binarnym nie ma żadnych konwersji.
Nie zawsze – jest w DOS-ie, nie ma w UNIX-ie.

130

background image

Jak drukować (na pececie):

#include <fstream.h>

#define PRINTER ofstream("prn", ios::out)

int main()

{

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

PRINTER << i << endl;

// operacje

return 0;

}

131

background image

7

Wzorce

7.1

Wzorce klas

Wzorzec albo szablon, czyli template. Typ T jest tu „uniwersalnym”
typem dla różnych klas, otrzymywanych przez podstawienie za T
ustalonego typu.

#include <iostream.h>

template<class T> class stack

{

T* v;

T* p;

int sz;

132

background image

public:

stack(int s){v=p=new T[sz=s];}

~stack(){delete[] v;}

void push(T a){*p++=a;}

T pop(){return *--p;}

int size() const {return p-v;}

};

133

background image

main()

{

stack<char> sc(100);

stack<int> si(100);

sc.push(’a’);

si.push(100);

cout << sc.pop() << endl;

cout << si.pop() << endl;

}

7.2

Wzorce funkcji

Moża też definiować wzorce funkcji globalnych.

134

background image

#include <iostream.h>

template<class T> void swap(T v[], int i, int j)

{

T tmp;

tmp=v[i];

v[i]=v[j];

v[j]=tmp;

}

template<class T>

void q_sort(T t[],

int left, int right)

135

background image

{

int i,last;

if(left>=right) return;

swap(t,left,(left+right)/2);

last=left;

for(i=left+1;i<=right;i++)

{

if(t[i]<t[left])

{

swap(t,++last,i);

}

}

136

background image

swap(t,left,last);

q_sort(t,left,last-1);

q_sort(t,last+1,right);

}

int main()

{

int a[]={3,1,2};

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

q_sort(a,0,2);

q_sort(b,0,2);

cout << a[0] << a[1] << a[2] << endl;

137

background image

cout << b[0] << b[1] << b[2] << endl;

return 0;

}

Daje w wyniku:

123

123

Jest to tylko najprostszy przykład!

138

background image

8

Aplety Javy – początki

8.1

Strona WWW apletu

Na podstawie [

11

].

Wszytkie pokazane programy są drobnymi modyfikacjami programów z
[

11

].

Program (aplet) hello.java włączany do strony WWW w języku html.
Jeśli przeglądarka nie obsługuje Javy, to aplet jest ignorowany.
Trudno obecnie taką przeglądarkę spotkać.

139

background image

import java.awt.Graphics;

/** Pierwszy aplet w Javie */

public class hello extends java.applet.Applet

{

public void paint(Graphics g)

{

g.drawString("Nie żyje Java", 60,30);

}

}

Kompilacja javac hello.java, otrzymujemy hello.class.

140

background image

Następnie budujemy stronę WWW.

<html>

<!- Strona WWW napisana dla Sun Applet Viewer >

<head>

<title>hello</title>

</head>

<body>

<hr>

<applet

141

background image

code=hello.class

width=200

height=200>

</applet>

<hr>

</body>

</html>

Uruchamiamy przy pomocy programu AppletViewer:

appletviewer hello.htm

142

background image

Uwaga 1. Nie ma metody main(), nie można więc uruchomić
programu poleceniem java.
Uwaga 2. Poleceniem javadoc tworzymy dokumentację w postaci
plików .html.

143

background image

8.2

Pola tekstowe

import java.awt.*;

public class text extends java.applet.Applet

{

TextField text1;

public void init()

{

text1 = new TextField(20);

add(text1);

text1.setText("Niech żyje Java");

}

}

144

background image

Wybrane metody klasy TextField

getText

Pobiera tekst

setText

Wprowadza tekst

processActionEvent(ActionEvent) Przetwarza

zdarzenia

akcji, wysyłając je do

ActionListener

Funkcja init uruchamia się automatycznie, gdy startuje aplet. Funkcja
init nie zwraca wartości.

145

background image

8.3

Przyciski

Jeden przycisk.

import java.applet.Applet;

import java.awt.*;

import java.awt.event.*;

public class clicker extends Applet implements ActionListener {

TextField text1;

Button button1;

public void init(){

text1 = new TextField(20);

146

background image

add(text1);

button1 = new Button("Kliknij tutaj!");

add(button1);

button1.addActionListener(this);

}

public void actionPerformed(ActionEvent event){

String msg = new String ("Niech żyje Java");

if(event.getSource() == button1){

text1.setText(msg);

}

}

}

147

background image

Wybrane metody klasy Button

Button()

Tworzy przycisk bez
etykiety

Button(String)

Tworzy przycisk z po-
daną etykietą

addActionListener(ActionListener)

Wprowadza słuchacza
akcji

removeActionListener(ActionListener) Usuwa słuchacza akcji

processActionEvent(ActionEvent)

Przetwarza zdarzenia
akcji, wysyłając je do

ActionListener

148

background image

Wybrane metody klasy String

String()

Tworzy nowy łańcuch
tekstowy

String(String)

Tworzy nowy łańcuch
tekstowy z zawartości
podanego łańcucha

length()

Zwraca

długość

łańcucha

substring(int,int) Zwraca podłańcuch

valueOf(n)

łańcuch

określający

liczbę n

149

background image

Dwa przyciski.

import java.applet.Applet;

import java.awt.*;

import java.awt.event.*;

public class clickers extends Applet implements ActionListener {

TextField text1;

Button button1, button2;

public void init(){

text1 = new TextField(20);

150

background image

add(text1);

button1 = new Button("Niech żyje");

add(button1);

button1.addActionListener(this);

button2 = new Button("Java");

add(button2);

button2.addActionListener(this);

}

public void actionPerformed(ActionEvent e){

if(e.getSource() == button1){

text1.setText("Niech żyje");

151

background image

}

if(e.getSource() == button2){

text1.setText("Java");

}

}

}

152

background image

Zobaczmy co się stanie, gdy w pliku .htm zmienimy wiersze

width=200

height=200

na

width=400

height=400

153

background image

8.4

Obszary tekstowe

Obszary tekstowe działają podobnie jak pola tekstowe, ale mają
możliwość pracy z wieloma wierszami tekstu.
Umożliwia utworzenie obszru tekstowego o danej liczbie wiersz i kolumn,
z paskami przewijania oraz możliwościami edycji tekstu.

154

background image

import java.applet.Applet;

import java.awt.*;

import java.awt.event.*;

public class txtarea extends Applet implements ActionListener {

TextArea textarea1;

Button button1;

public void init(){

textarea1 = new TextArea("", 5, 20);

add(textarea1);

155

background image

button1 = new Button("Kliknij tutaj!");

add(button1);

button1.addActionListener(this);

}

public void actionPerformed (ActionEvent e){

String msg = "Niech żyje Java";

if(e.getSource() == button1){

textarea1.insert(msg, 0);

}

}

}

156

background image

Wybrane metody klasy TextArea

TextArea()

Tworzy nowy obszar
tekstowy

TextArea(String) Tworzy nowy obszar

tekstowy z podanym
tekstem

TextArea()

Tworzy nowy obszar
tekstowy z podanym
tekstem oraz podaną
liczbą wierszy i kolumn

append(String)

Dołącza

tekst

na

końcu obszaru

157

background image

9

Konstruktory kopiujące i funkcje wirtualne

9.1

Konstruktory kopiujące

Konstruktor kopiujący w danej klasie Klasa jest postaci

Klasa::Klasa(Klasa &)

Konstruktor taki służy do skonstruowania obiektu, który jest kopią
innego, już istniejącego.
Wywołanie jawne:

Klasa obiekt_wzor; // wcześniej zdefiniowany

// wzór klasy Klasa

Klasa obiekt_nowy=Klasa(obiekt_wzor); // def. nowego

158

background image

#include <iostream.h>

#include <string.h>

class f_lin {

float a, b;

// wspolczynniki rownania

char nazwa[80] ; // nazwa (opis) rownania

public :

// konstruktor

f_lin(float wsp_a, float wsp_b, char* txt);

159

background image

//konstruktor kopiujacy

f_lin(f_lin &);

float v_lin(float x)

{

return a*x+b;

}

char* opis() {return nazwa;}

} ;

160

background image

f_lin::f_lin(float wsp_a,float wsp_b,char * txt ):

a(wsp_a), b(wsp_b)

{

strcpy(nazwa, txt) ;

}

f_lin::f_lin(f_lin & f1)

{

a = f1.a ;

b = f1.b ;

// zamiast :

strcpy(nazwa, wzorzec.nazwa) ;

161

background image

strcpy(nazwa,

"KONSTRUKTOR KOPIUJACY");

}

void fun_1(f_lin rec) ;

f_lin fun_2(void) ;

/*******************************************************/

main()

{

f_lin g(2.0, 1.0, "Funkcja g");

// Rozne warianty tego samego

162

background image

f_lin

h(g);

//f_lin

h = f_lin(g) ;

//f_lin

h = g ;

cout << "Podaj x: " ;

float x ;

cin

>> x ;

cout << "\nWedlug funkcji liniowej g, \nopisanej jako "

<< g.opis()

<< "\nargumentowi x=" << x

163

background image

<< " odpowiada wartosc "

<< g.v_lin(x) << endl ;

cout << "\nWedlug funkcji liniowej h, \nopisanej jako "

<< h.opis()

<< "\nargumentowi x= " << x

<< " odpowiada wartosc "

<< h.v_lin(x) << endl ;

cout <<"\nDo fun_1 wysylam funkcje liniowa "

<< g.opis() << endl ;

164

background image

fun_1(g) ;

cout << "\nTeraz wywolam fun_2, a jej"

" rezultat\n"

"podstawie do innej funkcji liniowej \n" ;

cout << "Obiekt chwilowy zwrocony jako "

"rezultat funkcji \nma opis "

<< ( fun_2() ).opis()

<< endl ;

}

/*******************************************************/

165

background image

void fun_1(f_lin rec)

{

cout << "Natomiast w fun_1 "

"odebralem te funkcje liniowa\n"

"opisana jako "

<< rec.opis()

<< endl ;

}

/*******************************************************/

f_lin fun_2(void)

{

f_lin w(0, 0, "Funkcja w") ;

166

background image

cout << "W funkcji fun_2 definiuje funkcje liniowa"

" i ma \nona opis "

<< w.opis() << " i wartosc "

<< w.v_lin(1) << " w punkcie x=1"

<< endl ;

return w;

}

167

background image

Program ten daje następujący efekt:

Podaj x: 0.3

Wedlug funkcji liniowej g,

opisanej jako Funkcja g

argumentowi x=0.3 odpowiada wartosc 1.6

Wedlug funkcji liniowej h,

opisanej jako KONSTRUKTOR KOPIUJACY

argumentowi x= 0.3 odpowiada wartosc 1.6

168

background image

Do fun_1 wysylam funkcje liniowa Funkcja g

Natomiast w fun_1 odebralem te funkcje liniowa

opisana jako KONSTRUKTOR KOPIUJACY

Teraz wywolam fun_2, a jej rezultat

podstawie do innej funkcji liniowej

W funkcji fun_2 definiuje funkcje liniowa i ma

ona opis Funkcja w i wartosc 0 w punkcie x=1

Obiekt chwilowy zwrocony jako rezultat funkcji

ma opis KONSTRUKTOR KOPIUJACY

169

background image

Dokładna kopia powstaje przy inicjalizacji nowego obiektu za pomocą
automatycznie generowanego konstruktora kopiującego. Przykład
skopiowany z książki Symfonia C++.

#include <iostream.h>

#include <string.h>

class wizytowka {

public :

char *nazw ;

char *imie ;

// konstruktor

wizytowka(char * na, char * im) ;

170

background image

// destruktor

wizytowka::~wizytowka() ;

void personalia() {

cout << imie << " " << nazw << endl ;

}

//-----------

void zmiana_nazwiska(char *nowe)

{

strcpy(nazw, nowe);

}

} ;

171

background image

// definicja konstruktora

wizytowka::wizytowka(char *im, char *na)

{

nazw = new char [80] ;

strcpy(nazw, na) ;

imie = new char [80] ;

strcpy(imie, im) ;

}

172

background image

// definicja destruktora

wizytowka::~wizytowka()

{

delete nazw ;

delete imie ;

}

main()

{

wizytowka fizyk( "Albert", "Einstein") ;

wizytowka kolega = fizyk ;

173

background image

cout << "Po utworzeniu blizniaczego obiektu oba "

"zawieraja nazwiska\n" ;

fizyk.personalia();

kolega.personalia();

// moj kolega nazywa sie naprawde Albert Metz

kolega.zmiana_nazwiska("Metz");

cout << "\nPo zmianie nazwiska kolegi brzmi ono : ";

174

background image

kolega.personalia();

cout << "Tymczasem niemodyfikowany fizyk"

" nazywa sie : " ;

fizyk.personalia();

}

175

background image

Program ten daje następujący efekt:

Po utworzeniu blizniaczego obiektu oba zawieraja nazwiska

Albert Einstein

Albert Einstein

Po zmianie nazwiska kolegi brzmi ono : Albert Metz

Tymczasem niemodyfikowany fizyk nazywa sie : Albert Metz

176

background image

Jak na to poradzić? Piszemy własny konstruktor kopiujący.

wizytowka::wizytowka(wizytowka & wzor)

{

nazw = new char [80] ;

strcpy(nazw, wzor.nazw) ;

imie = new char [80] ;

strcpy(imie, wzor.imie) ;

}

177

background image

Tak zmodyfikowany program da następujący wynik:

Po utworzeniu blizniaczego obiektu oba zawieraja nazwiska

Albert Einstein

Albert Einstein

Po zmianie nazwiska kolegi brzmi ono : Albert Metz

Tymczasem niemodyfikowany fizyk nazywa sie : Albert Einstein

178

background image

9.2

Funkcje wirtualne

Funkcja wirtualna poprzedzona jest słowem virtual. Nie może być
typu static.

/*--------------------------------------------------

cv.h

----------------------------------------------------*/

#include <iostream.h>

#include <math.h>

class fun0 {

protected:

float x;

179

background image

public:

void virtual v()

{

cout << x <<endl;

}

void arg(float xx) {

x=xx;

}

} ;

class fun1 : public fun0 {

public:

180

background image

void v()

{

cout << exp(x) <<endl;

}

}

;

class fun2 : public fun0 {

public:

void v()

{

cout <<

log(x) <<endl;

}

181

background image

}

;

class fun3 : public fun0 {

public:

void v()

{

cout << sqrt(x) <<endl;

}

}

;

#include "cv.h"

void f(fun0 & fun_e) ;

/*******************************************************/

182

background image

main()

{

fun0

f0;

fun1

f1;

fun2

f2;

fun3

f3;

cout << "Podaj x: " ;

float x ;

cin

>> x ;

183

background image

f0.arg(x);

f1.arg(x);

f2.arg(x);

f3.arg(x);

cout << "Zwykle wywolania funkcji skladowych\n"

"na rzecz obiektow\n" ;

f0.v() ;

f1.v() ;

f2.v() ;

f3.v() ;

184

background image

cout << "Wywolanie funkcji na rzecz obiektu \n"

"pokazywanego wskaznikiem funkcji fun0\n" ;

fun0 *ptrfun ;

// ustawienie wskaznika

ptrfun = & f0;

ptrfun-> v() ;

185

background image

cout << "Rewelacja okazuje sie przy "

"pokazaniu wskaznikiem\ndo funkcji"

" na obiekty klas pochodnych\n"

" od klasy fun ! \n" ;

ptrfun = &f1;

ptrfun-> v() ;

ptrfun = &f2 ;

ptrfun-> v() ;

ptrfun = &f3 ;

186

background image

ptrfun-> v() ;

cout << "Podobne zachowanie jest takze \n"

"w stosunku do referencji \n" ;

f(f0);

f(f1);

f(f2);

f(f3);

}

/*******************************************************/

187

background image

void f(fun0 & fun_e)

{

fun_e.v();

}

188

background image

Wynik działania programu:

Podaj x: 4

Zwykle wywolania funkcji skladowych

na rzecz obiektow

4

54.5982

1.38629

2

Wywolanie funkcji na rzecz obiektu

pokazywanego wskaznikiem funkcji fun0

4

Rewelacja okazuje sie przy pokazaniu wskaznikiem

189

background image

do funkcji na obiekty klas pochodnych

od klasy fun !

54.5982

1.38629

2

Podobne zachowanie jest takze

w stosunku do referencji

4

54.5982

1.38629

2

190

background image

Po pominięciu słowa virtual, czyli

class fun0 {

protected:

float x;

public:

void v()

{

cout << x <<endl;

}

void arg(float xx) {

x=xx;}

} ;

191

background image

otrzymujemy

Podaj x: 4

Zwykle wywolania funkcji skladowych

na rzecz obiektow

4

54.5982

1.38629

2

Wywolanie funkcji na rzecz obiektu

pokazywanego wskaznikiem funkcji fun0

4

192

background image

Rewelacja okazuje sie przy pokazaniu wskaznikiem

do funkcji na obiekty klas pochodnych

od klasy fun !

4

4

4

Podobne zachowanie jest takze

w stosunku do referencji

4

4

4

4

193

background image

Wirtualny – możliwy, mogący zaistnieć. Funkcja oznaczona jako
wirtualna, może (nie musi) być zrealizowana w klasach pochodnych
jeszcze raz inaczej. Bez słowa virtual będzie jak w ostatnim
przykładzie.
Konstruktory nie mogą być virtualne, ale destruktory powinny.
Jeśli klasa deklaruje jedną ze swoich funkcji jako virtual wówczas
destruktor deklarujemy też jako virtual.

194

background image

class fun0 {

protected:

float x;

public:

void virtual v()

{

cout << x <<endl;

}

void arg(float xx) {

x=xx;

}

virtual ~fun0();

195

background image

} ;

class fun1 : public fun0 {

public:

void v()

{

cout << exp(x) <<endl;

}

~fun1(); // też jest virtualny!

}

;

196

background image

Polimorfizm – wielopostaciowość: fragment kodu, w którym wywołuje się
funkcję wirtualną.
Mając tylko wersję binarną (skompilowaną) funkcji f oraz plik
nagłówkowy cv.h można napisać nową klasę

class fun_spec : public fun0 {

public:

void v()

{

cout << sqrt(exp(x)) <<endl;

}

}

;

i wywołać ją w programie

197

background image

#include "cv.h"

main()

{

fun_spec fs;

fs.arg(4);

f(fs);

}

W rezultacie otrzyma się wynik

e

4

.

Funkcja wirtualna nie może być klasy static.

198

background image

Klasa abstrakcyjna to klasa, która nie reprezentuje żadnego konkretnego
obiektu. Na przykład funkcja (tak w ogóle) może być klasą podstawową
dla konkretnych funkcji.

#include <iostream.h>

class fun

{

protected:

double x;

double y;

public:

void dane(double xx,double yy){x=xx;y=yy;}

199

background image

double virtual funkcja()=0; // czysto abstrakcyjna

};

class wykladnicza : public fun

{

public:

double funkcja(){return exp(x)+exp(y);}

};

class logarytmiczna : public fun

{

public:

200

background image

double funkcja(){return log(x)+log(y);}

};

main()

{

wykladnicza w;

logarytmiczna l;

fun* wskfun;

wskfun=&w;

wskfun->dane(0,0);

201

background image

cout << wskfun->funkcja() << endl;

wskfun=&l;

wskfun->dane(1,1);

cout << wskfun->funkcja() << endl;

return 0;

}

w rezultacie otrzymuje się

2

0

202


Document Outline


Wyszukiwarka

Podobne podstrony:
r12-05, Programowanie, ! Java, Java Server Programming
r20-05, Programowanie, ! Java, Java Server Programming
Java i XML, programowanie, Java
O Autorach-05, Programowanie, ! Java, Java Server Programming
r05-05, Programowanie, ! Java, Java Server Programming
r07-05, Programowanie, ! Java, Java Server Programming
r03-05, Programowanie, ! Java, Java Server Programming
rE-05, Programowanie, ! Java, Java Server Programming
r19-05, Programowanie, ! Java, Java Server Programming
05-08, Programowanie, ! Java, Java i XML
r17-05, Programowanie, ! Java, Java Server Programming
02-08, Programowanie, ! Java, Java i XML
12-08, Programowanie, ! Java, Java i XML
r11-05, Programowanie, ! Java, Java Server Programming
rD-05, Programowanie, ! Java, Java Server Programming
Programista JAVA
00-08-orig, Programowanie, ! Java, Java i XML
rF-05, Programowanie, ! Java, Java Server Programming

więcej podobnych podstron