• Nie Znaleziono Wyników

Wykład 8 Obiektowe struktury danych - c.d. 1. Obiektowa struktura danych - stos jako dynamiczna rekurencyjna struktura danych 2. Szablony -wiadomości wstępne 3. Szablony obiektowych struktur danych 1.

N/A
N/A
Protected

Academic year: 2021

Share "Wykład 8 Obiektowe struktury danych - c.d. 1. Obiektowa struktura danych - stos jako dynamiczna rekurencyjna struktura danych 2. Szablony -wiadomości wstępne 3. Szablony obiektowych struktur danych 1."

Copied!
1
0
0

Pełen tekst

(1)

Wykład 8

Obiektowe struktury danych - c.d.

1. Obiektowa struktura danych - stos jako dynamiczna rekurencyjna struktura danych

2. Szablony -wiadomości wstępne

3. Szablony obiektowych struktur danych

1. Obiektowa struktura danych –

(2)

Przykład 1

poczatek

punkt ramka

n_ramka napis x,y

dlugosc wiersz

x, y

wysokosc dlugosc wiersz

*wiersz

*wiersz x,y,

dlugosc wysokosc

x, y NULL

stos

elem nast

elem

elem

elem nast

nast

nast

wezel

Obiekt typu stos zawiera wskaźnik poczatek wskazujący na dynamiczny

obiekt typu wezel zawierający dwa wskaźniki: elem wskazujący na obiekty z

danymi, pochodzące z rodziny praprzodka klasy abstrakcyjnej abstr oraz drugi

wskaźnik nast wskazujący na kolejny obiekt typu wezel. Obiekty z danymi

pochodzą z rodziny obiektów zastosowanej w przykładach 3 i 4 z wykładu 7. W

bieżącym przykładzie zastosowano jedynie inną strukturę do przechowania tych

samych obiektów - dynamiczną rekurencyjną strukturę danych typu stos.

(3)

#include "nram7_2.h"

#include "stos8_1.h"

...

void wyswietl(punkt*);

void wyswietl(abstr*);

void wyswietl(float, char * kom);

void main()

{ { n_ramka *n_r1, *n_r2;

ramka* r1,*r2;

napis* n1,*n2;

punkt* p1,*p2;

stos Stos;

abstr* p;

n_r1 = new n_ramka(36,10,19,8,"napis w ramce_1",0x3A); Stos.wstaw(n_r1);

n_r2 = new n_ramka(54,8,19,5,"napis w ramce_2",0x1B); Stos.wstaw(n_r2);

r1 = new ramka(50,12,10,8); Stos.wstaw(r1);

r2 = new ramka(60,9,10,5); Stos.wstaw(r2);

n1 = new napis(50,21,"napis1"); Stos.wstaw(n1);

n2 = new napis(63,18,"napis2"); Stos.wstaw(n2);

p1 = new punkt(12,13); Stos.wstaw(p1);

p2 = new punkt(12,8); Stos.wstaw(p2);

/*sposób odwołania do metod wirtualnych p_dlugosc klas ramka i punkt w celu odczytu dwóch pól o tej samej nazwie dlugosc dziedziczonych przez obiekt typu n_ramka od klasy ramka i napis - przy takim odwołaniu kompilator ustala adres

metod wirtualnych podczas kompilacji; */

cout << n_r1->napis::p_dlugosc()<<' ';

cout << n_r1->ramka::p_dlugosc()<<' ';

/*sposób odwołania do dwóch pól dlugosc dziedziczonych od klas ramka i punkt w celu odczytu ich wartości - możliwy przy dostępie public do składowych*/

cout<<n_r1->napis::dlugosc<<' ';

cout<<n_r1->ramka::dlugosc<<" \n";

/*1. W metodzie wirtualnej wyswietl, czystej w klasie abstr, przedefiniowanej i

dziedziczonej od klasy punkt oraz w niezależnej funkcji wyswietl dostęp do jednej z

(4)

wynika z kolejności umieszczenia klas bazowych w liście dziedziczenia w klasie

n_ramka */

/*2. Metoda stosu dla stosu o elementach typu abstr i parametrem abstr; posiadającego funkcję niezależną o nagłówku void(*)(abstr*) np. wyswietl(abstr*)

Stos.Dla _kazdego(wyswietl); //dzięki polimorfizmowi klasy abstrakcyjnej while (!Stos.pusty())

{

p=Stos.usun();

--(*p);--(*p); //dzięki polimorfizmowi klasy abstrakcyjnej p->wyswietl(„\nmetoda”); //dzięki polimorfizmowi klasy abstrakcyjnej wyswietl((punkt*)p); //dzięki polimorfizmowi klasy wirtualnej punkt wyswietl(((punkt*)p)->odleglosc(*n_r1),"");

}

Stos.wstaw(n_r1); Stos.wstaw(n_r2);

Stos.wstaw(r1); Stos.wstaw(r2);

Stos.wstaw(n1); Stos.wstaw(n2);

Stos.wstaw(p1); Stos.wstaw(p2);

Stos.Dla_kazdego(wyswietl);

/* dzięki polimorfizmowi klasy abstrakcyjnej wywołanie destruktora stosu - usuwanie elementów stosu, pochodnych klasy abstr, dzięki jej wirtualnemu destruktorowi, przedefiniowanemu w klasach pochodnych*/

} }...

/* uniwersalna funkcja do wyświetlania pól całej rodziny obiektów: punkt, ramka, napis oraz n_ramka dzięki:

przekazywaniu obiektów przez wskaźnik

zastosowaniu polimorfizmu, czyli wywoływaniu metod wirtualnych: p_dlugosc, p_wiersz, p_wysokosc, p_atrybuty */

void wyswietl(punkt* p)

{cout << "Atrybuty: " << p->p_atrybuty();

cout << " Wiersz: " << p->p_wiersz();

cout << " Dlugosc, Wysokosc: "<< p->p_dlugosc()<< " "<<p->p_wysokosc()<<" ";

cout << " Wspolrzedne: " << p->odcieta() << " "<< p->rzedna();

p->rysuj();.... }

void wyswietl(abstr* p) //funkcja do wyświetlania stosu elementów typu abstr*

{ --(*p);

p->wyswietl("");}

(5)

#include "abstr7_2.h" //zawartość pliku nagłówkowego stos8_1.h

#include <alloc.h>

class stos { struct wezel { abstr *elem;

wezel* nast;

wezel (abstr *x, wezel*y) {elem= x; nast= y;}

};

typedef wezel* polaczenie;

polaczenie poczatek;

public:

stos(int = NULL) {poczatek = NULL;}

~stos();

int pusty() {return poczatek==NULL;}

void wstaw(abstr *x)

{if (coreleft() >= sizeof(wezel))

poczatek = new wezel (x, poczatek);}

abstr* usun()

{if (!poczatek) return NULL;

abstr* v = poczatek->elem; polaczenie pom = poczatek->nast;

delete poczatek; poczatek=pom; return v;}

//uniwersalna metoda wykonująca dowolną funkcję o nagłówku void(*)(abstr*) na //elementach stosu

void Dla_kazdego(void (*p) (abstr*));

};

stos::~stos()

{ polaczenie pom= poczatek;

while (poczatek)

{ pom= poczatek->nast;

delete poczatek->elem;

delete poczatek;

poczatek= pom;}}

void stos::Dla_kazdego(void (*p)(abstr*)) { polaczenie pom= poczatek;

while(pom)

{ p(pom->elem);

pom= pom->nast;}}

(6)

2. Szablony - wiadomości wstępne

Szablon lub inaczej wzorzec (template) definiuje rodzinę typów lub funkcji.

deklaracja-wzorca:

template <lista-argumentów-wzorca> deklaracja lista-argumentów-wzorca:

argument-wzorca

lista-argumentow-wzorca, argument-wzorca argument-wzorca:

argument-typu

deklaracja-argumentu argument-typu:

class nazwa-typu

Deklaracja w deklaracji-wzorca musi deklarować lub definiować funkcję lub klasę.

Uwagi:

 Argument-typu definiuje nazwę typu obowiązującą w zasięgu deklaracji wzorca.

 Deklaracja-wzorca jest globalna i podlega zwykłym regułom zasięgu i kontroli dostępu, nazwa-typu obowiązuje w zasięgu deklaracji-wzorca.

 W programach wieloplikowych deklaracje szablonów powinny być zawarte w

plikach nagłówkowych ze względu na ich wieloużywalność! Nie można umieścić

definicji szablonu w pliku modułowym!

(7)

2.1. Szablony klas

Deklarowanie i definiowanie wzorca klasy Przykład - Deklaracja wzorca klasy wektor o parametrze T.

template <class T> class wektor { T * p; int ile;

public: wektor (int)

T& element(int i) {return p[i]};

T& operator[] (int); //... };

Klasę można zadeklarować następująco:

nazwa-klasy-wzorca:

nazwa-wzorca <lista-arg-wzorca>

lista-arg-wzorca:

arg-wzorca

lista-arg-wzorca, arg-wzorca arg-wzorca:

wyrażenie nazwa-typu

Nazwa-klasy-wzorca (np. wektor) musi być unikatowa w programie. Typy argumentów-wzorca wyspecyfikowane w nazwie-klasy-wzorca muszą pasować do typów podanych w liście-argumentów-wzorca. Argumentami-wzorca mogą być:

typy, wyrażenia-stałe, adresy obiektów lub funkcji łączonych zewnętrznie lub statyczne składowe klasy.

Korzystanie z wzorca klasy 1) generowanie klas wzorca na podstawie danego szablonu

wektor<int> w1(20)

wektor<complex> w2(30)

typedef wektor<complex> cwekt; //cwekt synonimem wektor<complex>

cwekt w3(40);

w2[1] = w3.element(4) = complex(7, 8);

2) używanie nazwy-klasy-wzorca wszędzie tam, gdzie można używać nazwy klasy : class wektor<Punkt*>;

wektor<Ramka>* biezaca_ramka;

class wektor_fig : public wektor<Punkt*> {...};

Definiowanie metod klasy wzorca

Metoda klasy wzorca jest niejawnie funkcją wzorca, której argumentami są argumenty wzorca jej klasy:

template<class T> T& wektor<T>::operator[](int i) {...}

(8)

2.2. Szablony funkcji

Wzorzec funkcji specyfikuje, jak można konstruować poszczególne funkcje.

Specyfikuje on nieograniczony zbiór (przeciążonych) funkcji.

Każdy argument-wzorca podany w liście-argumentów wzorca musi być użyty jako argument we wzorcu funkcji.

Generowanie funkcji wzorca Np. rodzinę funkcji sortujących można zadeklarować:

template<class T> void sortuj(wektor<T>& w)

{tutaj można używać metod obiektu w klasy wektor<T> oraz typu T}

wektor<complex> wc(100);

wektor<int> wi(200);

void f (wektor<complex>& wc, wektor<int>& wi) { sortuj(wc); sortuj(wi); }

Dopasowanie argumentów template<class T> T max (T a, T b)

{return a>b ? a : b;};

void f (int a, int b, char c, char d) {

int m1 = max (a, b);

int m2 = max (c, d);

int m3 = max (a, c); //błąd: nie można wygenerować max(int, char) }

Błędne deklaracje i definicje wzorca funkcji:

template<class T> T* utworz();

template<class T> void f() { T a... }

Zasady rozstrzygania dla funkcji wzorca i innych funkcji o tej samej nazwie:

 dokładne dopasowanie funkcji

 lub dokładne dopasowanie wzorca, z którego można wygenerować funkcję

 lub zwykły algorytm rozstrzygania przeciążenia funkcji

(9)

Przykład - wzorzec funkcji sortującej bąbelkowo

const n= 5;

template <class T> void sortuj (T *w, const int ile);

void main() {

int t1[n] ={2,1,4,3,5};

float t2[n] = {3.2, 1.2, 5.3, 6.4, 4.5};

sortuj(t1, n); //wywołanie kodu funkcji sortuj dla tablicy elementów typu int sortuj(t2, n); //wywołanie kodu funkcji sortuj dla tablicy elementów typu float }

// wzorzec funkcji, który stanie się kodem konkretnej funkcji, jeżeli kompilator // zauważy wywołanie wzorca z konkretnymi danymi zamiast parametru T

template <class T> void sortuj (T *w, const int ile)

{

for (int i= 0; i < ile-1; i++) for (int j=0; j <ile-1-i; j++)

if (w[j] > w[j+1]) { T pom = w[j];

w[j] = w[j+1];

w[j+1]= pom;}

};

(10)

3. Szablony obiektowych struktur danych

Szablony uniwersalnych obiektowych struktur danych umożliwiają powielanie kodu dla różnych typów elementów przechowywanych w tych strukturach:

pochodzących z różnych „rodzin” obiektowych lub typów podstawowych (int, float itp.).

Przykład 2 - szablon stosu jako tablicy dynamicznych elementów - parametrów szablonu (dotyczy przykładu 4 z wykładu 7)

#include "nram7_2.h"

#include "tstos7_3.h"

...

void wyswietl(punkt*);

void wyswietl(abstr*);

void wyswietl(int*);

void wyswietl(float, char * );

void main()

{ { //wygenerowana klasa stos o elementach typu wskaźniki na int i obiekt ST stos <int> ST(4);

int *l;

l = new int; *l = 1; ST.wstaw(l);

l = new int; *l = 2; ST.wstaw(l);

l = new int; *l = 3; ST.wstaw(l);

l = new int; *l = 4; ST.wstaw(l);

/*metoda stosu o elementach typu int (parametr int); posiadającego dowolną funkcję niezależną o nagłówku void(*)(int*) np. wyswietl(int*)*/

ST.Dla_kazdego(wyswietl);

n_ramka *n_r1, *n_r2;

ramka* r1,*r2;

napis* n1,*n2;

punkt* p1,*p2;

/*wygenerowana klasa stos o elementach typu wskaźniki na obiekty z rodziny klasy abstr i obiekt Stos */

stos <abstr> Stos(8);

abstr* p;

n_r1 = new n_ramka(36,10,19,8,"napis w ramce_1",0x3A); Stos.wstaw(n_r1);

n_r2 = new n_ramka(54,8,19,5,"napis w ramce_2",0x1B); Stos.wstaw(n_r2);

r1 = new ramka(50,12,10,8); Stos.wstaw(r1);

r2 = new ramka(60,9,10,5); Stos.wstaw(r2);

n1 = new napis(50,21,"napis1"); Stos.wstaw(n1);

n2 = new napis(63,18,"napis2"); Stos.wstaw(n2);

(11)

/*metoda stosu o elementach typu abstr (parametr abstr); posiadającego funkcję niezależną o nagłówku void(*)(abstr*) np. wyswietl(abstr*)

Stos.Dla_kazdego(wyswietl);

while (!Stos.pusty()) {

p=Stos.usun();

--(*p); //dzięki polimorfizmowi klasy abstrakcyjnej p->wyswietl(""); //dzięki polimorfizmowi klasy abstrakcyjnej wyswietl(p); //dzięki polimorfizmowi klasy abstrakcyjnej wyswietl(((punkt*)p)->odleglosc(*n_r1),"");

}

/*wygenerowana klasa stos o elementach typu wskaźniki na obiekty z rodziny klasy punkt i obiekt Stos_ */

stos <punkt> Stos_(8);

punkt* p_;

Stos_.wstaw(n_r1);

Stos_.wstaw(n_r2);

Stos_.wstaw(r1);

Stos_.wstaw(r2);

Stos_.wstaw(n1);

Stos_.wstaw(n2);

Stos_.wstaw(p1);

Stos_.wstaw(p2);

/*metoda stosu o elementach typu punkt (parametr punkt); posiadającego funkcję niezależną o nagłówku void(*)(punkt*) np. wyswietl(punkt*)*/

Stos_.Dla_kazdego(wyswietl);

while (!Stos_.pusty()) {

p_= Stos_.usun();

--(*p_); //dzięki polimorfizmowi klasy wirtualnej punkt p_->wyswietl(""); //dzięki polimorfizmowi klasy wirtualnej punkt wyswietl(p_); //dzięki polimorfizmowi klasy wirtualnej punkt wyswietl(p_->odleglosc(*n_r1),"");

//wywołanie wirtualnych destruktorów z klasy aktualnych obiektów z rodziny punkt delete p_;

}

/*Dzięki destruktorowi klasy stos został usunięty stos ST elementów typu int.

Destruktory obiektów Stos i Stos_ usunęły jedynie dynamiczne tablice wskaźników w obu stosach, ponieważ obiekty z rodziny punkt zostały odłączone od nich (pętle

while) oraz usunięte z pamięci (druga pętla while) */

} }

/* uniwersalna funkcja do wyświetlania pól całej rodziny obiektów: punkt, ramka, napis

(12)

przekazywaniu obiektów przez wskaźnik

zastosowaniu polimorfizmu, czyli wywoływaniu metod wirtualnych: p_dlugosc, p_wiersz, p_wysokosc, p_atrybuty

*/

void wyswietl(punkt* p) {

cout << "Atrybuty: " << p->p_atrybuty();

cout << " Wiersz: " << p->p_wiersz();

cout << " Dlugosc, Wysokosc: "<< p->p_dlugosc()<< " "<<p->p_wysokosc()<<" ";

cout << " Wspolrzedne: " << p->odcieta() << " "<< p->rzedna();

p->rysuj();....

}

//funkcja do wyświetlania stosu elementów typu abstr*

void wyswietl(abstr* p) { --(*p);

p->wyswietl("");

}

//funkcja do wyświetlania stosu elementów typu int*

void wyswietl(int* w) {

cout << *w << "\n";

getch();

}

(13)

#ifndef STOS.H //zawartość pliku nagłówkowego tstos7_3.h

#define STOS.H

#include "abstr7_2.h"

const maxN=8;

template <class T>

class stos {

public:

typedef T* TT;

TT *elem; //elem jako wskaźnik dla dynamicznej tablicy wskaźników TT int ile; //liczba elementów wstawionych do tablicy

int rozmiar; //maksymalny rozmiar tablicy dynamicznej wskaźników TT stos(int max)

{ (max<=0) ? (rozmiar = maxN) : (rozmiar = max);

elem = new TT [rozmiar]; ile = 0;}

~stos();

int pusty() {return ile == 0;}

void wstaw(TT x)

{if ( ile < rozmiar) elem[ile++] = x;}

TT usun()

{ if (ile) return elem[--ile];

else return NULL;}

//uniwersalna metoda wykonująca dowolną funkcję p o nagłówku void(*)(T*) na //elementach stosu

void Dla_kazdego(void (*p) (T*)) };

template <class T>

void stos<T>::Dla_kazdego(void (*p) (T*)) { int i=ile;

while(i>0) p(elem[--i]);}

template <class T>

stos<T>::~stos() {int i=ile;

while(i>0) delete elem[--i];

delete elem;}

#endif

(14)

Przykład 3 - szablon stosu jako struktury dynamicznej typu stos przechowującej dynamiczne elementy, występujące jako parametr szablonu ( dotyczy przykładu 1)

Program ten ma postać podobną do programu z szablonem tablicy z przykładu 2.

#include "nram7_2.h"

#include "tstos8_1.h"

...

void wyswietl(punkt*); //funkcje jak w przykładzie 2 void wyswietl(abstr*);

void wyswietl(int*);

void wyswietl(float, char * kom);

void main()

{ { stos<int> ST;

int * l;

l = new int; *l = 1; ST.wstaw(l);

l = new int; *l = 2; ST.wstaw(l);

l = new int; *l = 3; ST.wstaw(l);

l = new int; *l = 4; ST.wstaw(l);

ST.Dla_kazdego(wyswietl); //uwaga z przykładu 2 n_ramka *n_r1, *n_r2;

ramka* r1,*r2;

napis* n1,*n2;

punkt* p1,*p2;

stos <abstr> Stos;

abstr* p;

n_r1 = new n_ramka(36,10,19,8,"napis w ramce_1",0x3A); Stos.wstaw(n_r1);

n_r2 = new n_ramka(54,8,19,5,"napis w ramce_2",0x1B); Stos.wstaw(n_r2);

r1 = new ramka(50,12,10,8); Stos.wstaw(r1);

r2 = new ramka(60,9,10,5); Stos.wstaw(r2);

n1 = new napis(50,21,"napis1"); Stos.wstaw(n1);

n2 = new napis(63,18,"napis2"); Stos.wstaw(n2);

p1 = new punkt(12,13); Stos.wstaw(p1);

p2 = new punkt(12,8); Stos.wstaw(p2);

Stos.Dla_kazdego(wyswietl);

while (!Stos.pusty()) { p= Stos.usun();

--(*p); //dzięki polimorfizmowi klasy abstrakcyjnej p->wyswietl(""); //dzięki polimorfizmowi klasy abstrakcyjnej wyswietl(p); //dzięki polimorfizmowi klasy abstrakcyjnej

(15)

stos <punkt> Stos_;

punkt* p_;

Stos_.wstaw(n_r1);

Stos_.wstaw(n_r2);

Stos_.wstaw(r1);

Stos_.wstaw(r2);

Stos_.wstaw(n1);

Stos_.wstaw(n2);

Stos_.wstaw(p1);

Stos_.wstaw(p2);

Stos_.Dla_kazdego(wyswietl);

while (!Stos_.pusty()) { p=Stos_.usun();

--(*p_); //dzięki polimorfizmowi klasy wirtualnej punkt p_->wyswietl(""); //dzięki polimorfizmowi klasy wirtualnej punkt wyswietl(p_); //dzięki polimorfizmowi klasy wirtualnej punkt wyswietl(p_)>odleglosc(*n_r1),"");

delete p_;

}

}}...

...

(16)

#ifndef STOS.H //zawartość pliku nagłówkowego tstos8_1.h

#define _STOS.H

#include "abstr7_2.h"

#include <alloc.h>

template <class T> class stos { struct wezel

{ T *elem;

wezel* nast;

wezel (T * x, wezel* y) {elem = x; nast = y;} };

typedef wezel* polaczenie;

polaczenie poczatek;

public:

stos(int = NULL) {poczatek = NULL;}

~stos();

int pusty() {return poczatek == NULL;}

T* usun()

{if (!poczatek) return NULL;

T* v = poczatek->elem;

polaczenie pom = poczatek->nast;

delete poczatek;

poczatek = pom; return v;}

void wstaw(T *x)

{ if (coreleft() >= sizeof(wezel)) poczatek = new wezel (x, poczatek);}

//uniwersalna metoda wykonująca dowolną funkcję p o nagłówku void(*)(T*) na //elementach stosu

void Dla_kazdego(void (*p)(T*));

};

template <class T>

void stos<T>::Dla_kazdego(void (*p)(T*)) { polaczenie pom = poczatek;

while(pom)

{ p(pom->elem); pom= pom->nast; } } template <class T>

stos<T>::~stos()

{ polaczenie pom = poczatek;

while (poczatek)

{ pom = poczatek->nast;

delete poczatek->elem; delete poczatek;

poczatek = pom;} }

Cytaty

Powiązane dokumenty

◮ parametry szablonu klasy bazowej muszą być parametrami szablonu klasy pochodnej albo muszą mieć ustaloną wartość. template&lt;class T,

Startujemy od mało efektywnego (naiwnego) algorytmu i konstruujemy algorytm efektywniejszy.. Transformacyjna

Jaki jest koszt wstawienia elementu do listy dwukierunkowej posortowanej?... Podstawowe struktury

Ćw3 Podstawowe struktury danych: kolejki, listy, stosy, kopce 3 Ćw4 Struktury drzewiaste: BST, AVL, B-R, B-drzewo 5 Ćw5 Algorytmy sortowania np.. Insertion-,

W teorii złożoności obliczeniowej fundamentalnym pojęciem jest problem

Każdy zbiór jest kolekcją tych obiektów, które pomyślnie przeszły test przynależności określony przez pojęcie. • Gdy stwierdzamy, że pojęcie stosuje się do

Do badania zawartości stron danych używamy instrukcji DBCC PAGE, która umożliwia oglądanie nagłówka strony, wierszy danych i tablicy przesunięć wierszy dla

Tabela (table) numeryczny, znakowy, zespolony, logiczny Nie Ramka