• Nie Znaleziono Wyników

Programowanie i struktury danych Programowanie i struktury danych

N/A
N/A
Protected

Academic year: 2021

Share "Programowanie i struktury danych Programowanie i struktury danych"

Copied!
10
0
0

Pełen tekst

(1)

Programowanie i struktury danych Programowanie i struktury danych

Wykład 8 Wykład 8

Dr Piotr Cybula <piotr.cybula@wmii.uni.lodz.pl>

Dr Piotr Cybula <piotr.cybula@wmii.uni.lodz.pl>

(2)

Struktury generyczne Struktury generyczne

Struktura tablicy dynamicznej o wartościach całkowitych:

struct Array { private:

int *array;

int size;

public:

Array(int _size = 10)

{ size = _size; array = new int[size];

} ~Array()

{ if(size > 0) delete [] array;

} int length() const { return size; }

int& operator[](int index) { return array[index]; } };

Array t(5);

t[0] = 7;

(3)

Struktury generyczne Struktury generyczne

Struktura tablicy dynamicznej o wartościach rzeczywistych:

struct Array { private:

float *array;

int size;

public:

Array(int _size = 10)

{ size = _size; array = new float[size];

} ~Array()

{ if(size > 0) delete [] array;

} int length() const { return size; }

float& operator[](int index) { return array[index]; } };

Array t(5);

t[0] = 7.5;

(4)

Programowanie generyczne Programowanie generyczne

realizowane w języku C++ w postaci struktur szablonowych (ang. templates)

szablony pozwalają na wielokrotne wykorzystanie istniejącego kodu źródłowego struktury danych dla wielu wersji tej struktury z tym samym interfejsem, ale różnymi typami dla wewnętrznych komponentów

(programowanie generyczne/uogólnione, struktury parametryzowane)

słowo kluczowe template jest informacją dla kompilatora, że struktura wykorzystuje nieokreślony typ danych będący parametrem tej struktury

podczas konkretyzacji (ang. instantiation) szablonu konkretnym typem kompilator zastępuje każde wystąpienie typu parametrycznego podanym typem i kompiluje strukturę danych (tzw. statyczny polimorfizm)

szablony mogą być parametryzowane typami lub wartościami (może być ich

wiele i mogą mieć wartości domyślne)

(5)

Struktura szablonowa Struktura szablonowa

Struktura tablicy dynamicznej będącej szablonem:

template<typename T> struct Array //template structure { private:

T *array; //T is a template parameter being a type int size;

public:

Array(int _size = 10)

{ size = _size; array = new T[size];

} ~Array()

{ if(size > 0) delete [] array;

} int length() const { return size; }

T& operator[](int index) { return array[index]; } };

Array<int> t1(5); Array<float> t2(10); //instantiations t1[0] = 7; t2[0] = 7.5;

(6)

Parametry szablonu Parametry szablonu

Struktura tablicy dynamicznej będącej szablonem dwuparametrowym:

template<typename T, int size = 10> struct Array //template { private:

T array[size]; //size is a template parameter being a value //size cannot be changed

public:

Array() {}

~Array() {}

int length() const { return size; }

T& operator[](int index) { return array[index]; } };

Array<int, 5> t1; //instantiation, size must be a constant Array<float> t2; //instantiation with default value for size Array<Student, 10> t3; //instantiation with a structure type t1[0] = 7;

t2[0] = 7.5;

cout << t2.length();

t3[0] = Student(”Scott Tiger”);

t3[0].setIndex(12345);

(7)

Metody szablonowe Metody szablonowe

przy implementacji metod struktury szablonowej poza strukturą używamy słowa kluczowego template z tymi samymi parametrami szablonu

(implementacja musi nastąpić w pliku nagłówkowym!)

template<typename T, int size>

T& Array<T, size>::operator[](int index) //template method { if(index < 0 || index >= size)

throw range_error("bad index");

return array[index];

}

//the result and the parameter types are templates template<typename T, int size>

Array<T, size>&

Array<T, size>::operator=(const Array<T, size>& arr) { if(this != &arr)

for(int i = 0; i < size; i++) array[i] = arr.array[i];

return *this;

}

(8)

Interfejs szablonu Interfejs szablonu

typowe określenie pasujące do szablonu: «przyjmę dowolny typ»

czasami implementacja metod szablonu wymusza pewne dodatkowe ograniczenia na przyjmowany typ, np. obecność pewnych metod dla typu będącego parametrem

ogólne określenie dla szablonu: «przyjmę dowolny typ wyposażony w ...»

Array<Student> t;

t.print(); //compile-time error, no operator<< for Student //after the declaration of the operator

ostream& operator<<(ostream &out, const Student &s) { ...

return out;

}

Array<Student> t;

t.print(); //OK

(9)

Pola szablonowe Pola szablonowe

template<typename T, int size>

struct NamedArray //structure with template field is template { private:

Array<T, size> array; //template field string name;

public:

NamedArray(string n);

T& operator[](int index);

T sum() const; //T must support operator+

T max() const; //T must support operator<

… //other methods };

NamedArray<float, 3> marks("My marks");

marks[0] = 4.5;

marks[1] = 5.0;

marks[2] = 4.0;

cout << marks.sum() / 3;

cout << marks.max();

cout << marks.length(); //compile-time error, hidden method

(10)

Szablony wielokrotne Szablony wielokrotne

struktura szablonowa może być parametryzowana typem szablonowym

w wersji kompilatora przed C++11 konieczne jest umieszczenie odstępu pomiędzy kolejnymi ostrymi nawiasami (> > zamiast >>)

//5-item array of 10-item arrays of integers //dynamic size version

Array< Array<int> > t(5);

//static size version

Array< Array<int, 10>, 5> t;

t[0][0] = 5;

cout << t.length();

cout << t[0].length();

Cytaty

Powiązane dokumenty

{ //składowe ukryte (słowo kluczowe private jest opcjonalne) string name;.

● wstawienie elementu do kolejki (push, enqueue), operacja możliwa gdy kolejka nie jest zapełniona (dotyczy typu o ograniczonym rozmiarze). ● pobranie elementu ze kolejki

przedostatniego węzła (ostatniego węzła, którego wskaźnik next jest niepusty) (3) ustawiamy dedykowany wskaźnik (killer) na ostatni węzeł używając adresu. zapisanego we

(1) powołujemy dwa pomocnicze wskaźniki: pred ustawiamy na pusty adres, a succ na adres pierwszego węzła (head) i przechodzimy nimi w kierunku końca listy tak, aby wskaźnik

(1) powołujemy dwa pomocnicze wskaźniki: pred ustawiamy na pusty adres, a succ na adres pierwszego węzła (head) i przechodzimy nimi w kierunku końca listy tak, aby wskaźnik pred

(2) za pomocą pary pomocniczych wskaźników pred i succ wybieramy węzeł do przeniesienia i przenosimy go do listy tymczasowej za pomocą wskaźnika mover (aktulizując wskaźniki head

● strumienie wejścia/wyjścia: iostream, fstream, sstream, iomanip. ●

(3) przestawiamy wskaźnik next w węźle wskazywanym przez pred (lub wskaźnik head gdy pred jest pusty) oraz wskaźnik prev w węźle wskazywanym przez succ (lub wskaźnik tail gdy