Stos liczb całkowitych

Podobne dokumenty
Szablony klas, zastosowanie szablonów w programach

Szablony funkcji i szablony klas

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Programowanie obiektowe. Wykład 5. C++: szablony

Operator przypisania. Jest czym innym niż konstruktor kopiujący!

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

FUNKCJE WZORCOWE. Wykład 10. Programowanie Obiektowe (język C++) Funkcje wzorcowe wprowadzenie (2) Funkcje wzorcowe wprowadzenie (1)

Abstrakcyjny typ danych

Programowanie 2. Język C++. Wykład 3.

Programowanie Obiektowe i C++

Wprowadzenie do szablonów szablony funkcji

C++ - [4-7] Polimorfizm

Wprowadzenie do szablonów szablony funkcji

Język C++ Programowanie obiektowe

Podstawy programowania obiektowego

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne

Programowanie 2. Język C++. Wykład 9.

Wykład V. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Konstruktor kopiujacy

PARADYGMATY PROGRAMOWANIA Wykład 4

Szablony. Szablony funkcji

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Szablony funkcji i klas (templates)

Wykład 1. Program przedmiotu. Programowanie Obiektowe (język C++) Literatura. Program przedmiotu c.d.:

Programowanie obiektowe - Przykładowe zadania egzaminacyjne (2005/2006)

Programowanie obiektowe Wykład 3. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21

Programowanie Obiektowe i C++

Programowanie w C++ Wykład 14. Katarzyna Grzelak. 3 czerwca K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27

C++ Przeładowanie operatorów i wzorce w klasach

Zaawansowane programowanie w języku C++ Funkcje uogólnione - wzorce

Klasy generyczne. ZbiórLiczb. ZbiórCzegokolwiek. Zbiór

Programowanie w języku C++

W dowolnym momencie można zmienić typ wskaźnika.

Programowanie obiektowe w C++ Wykład 12

EGZAMIN 2 (14 WRZEŚNIA 2015) JĘZYK C++

7. Pętle for. Przykłady

Język C++ wykład VIII

Wskaźnik może wskazywać na jakąś zmienną, strukturę, tablicę a nawet funkcję. Oto podstawowe operatory niezbędne do operowania wskaźnikami:

Wykład 4: Klasy i Metody

public: // interfejs private: // implementacja // składowe klasy protected: // póki nie będziemy dziedziczyć, // to pole nas nie interesuje

EGZAMIN PROGRAMOWANIE II (10 czerwca 2010) pytania i odpowiedzi

1 Wskaźniki i zmienne dynamiczne, instrukcja przed zajęciami

Funkcje przeciążone, konstruktory kopiujące, argumenty domyślne

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Dziedziczenie. Ogólna postać dziedziczenia klas:

Dynamiczne struktury danych

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

Programowanie w języku C++

Podstawy programowania w języku C++

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

Programowanie obiektowe w języku

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

Programowanie i struktury danych

Podstawy programowania obiektowego

PARADYGMATY PROGRAMOWANIA Wykład 2

Wskaźniki. nie są konieczne, ale dają językowi siłę i elastyczność są języki w których nie używa się wskaźników typ wskaźnikowy typ pochodny:

Wprowadzenie do szablonów klas

Zaawansowane programowanie w C++ (PCP)

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Technologie programowania Wykład 4. Szablony funkcji Notes. Szablony funkcji Notes. Szablony funkcji Notes. Notes. Przemek Błaśkiewicz.

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) { zdefiniuje. Integer::operator=(ri);

Dziedziczenie jednobazowe, poliformizm

Język C++ Różnice między C a C++

Programowanie Obiektowo Zorientowane w języku c++ Konstruktory

Jzyk C++ cz 3. Jarosław Gramacki Instytut Informatyki i Elektroniki ( $)*)+' *, - ( ' )*'.' '',*/ *, ','*0) 1 / ) %*+ 2'' 2" ( $%%) )'20 )*0) 1 / )

Wzorce funkcji (szablony)

Wykład 1. Program przedmiotu. Programowanie (język C++) Literatura. Program przedmiotu c.d.:

TEMAT : KLASY DZIEDZICZENIE

Zaawansowane programowanie w C++ (PCP)

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy PRAWA PRZYJACIÓŁ KLASY. Dostęp z zewnątrz: Dostęp z wewnątrz:

Programowanie obiektowe

Programowanie Obiektowew języku C++ Zadania L4

Programowanie w C++ Wykład 6. Katarzyna Grzelak. 1 kwietnia K.Grzelak (Wykład 6) Programowanie w C++ 1 / 43

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy KONSTRUKTORY

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

ZASADY PROGRAMOWANIA KOMPUTERÓW

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę.

ATD. Wykład 8. Programowanie (język C++) abstrakcyjny typ danych. Abstrakcyjne typy danych (ATD) Metody czysto wirtualne. Definicje i uwagi:

XV. Wskaźniki Odczytywanie adresu pamięci istniejących zmiennych Wskaźniki pierwsze spojrzenie.

Wprowadzenie do programowanie obiektowego w języku C++

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Zaawansowane programowanie w języku C++ Programowanie obiektowe

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 26 marca kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 40

Programowanie obiektowe i C++ dla matematyków

Hermetyzacja oraz pola i metody statyczne

#include <iostream.h> #include <conio.h>

Języki i techniki programowania Ćwiczenia 2

Programowanie obiektowe w C++ Wykład 07 Temat wiodący: Wzorce (szablony) klas, polimorfizm, funkcje wirtualne. Wzorce

Algorytmy i język C++

KURS C/C++ WYKŁAD 6. Wskaźniki

Abstrakcyjne struktury danych w praktyce

Transkrypt:

Stos liczb całkowitych class StosInt int* tab; unsigned size ; StosInt(unsigned s=10) tab=new int[size=s];top=0; ~StosInt()delete[] tab; void push(int i)tab[top++]=i; int pop(void) return tab[--top]; int empty() return!top; Stos napisów class StosString string* tab; unsigned size ; StosString(unsigned s=10) tab=new string[size=s];top=0; ~StosString()delete[] tab; void push(string el)tab[top++]=el; string pop(void) return tab[--top]; int empty() return!top; Zauważmy, że na stosie przechowujemy kopie. Nuda... Dla każdego typu musimy definiować nową klasę...... to nudne Możemy spróbować rozwiązać ten problem używając dziedziczenia, ale jak zobaczymy, to nie takie proste. 69

Rozwiązaniem, które dziś poznamy są wzorce (templates). Spróbujmy jednak najpierw z dziedziczeniem: // Podklasy tej klasy będą elementami stosu struct EltStosu virtual ~EltStosu() Stos elementów class Stos EltStosu** tab; unsigned size ; Stos(unsigned s=10) tab=new EltStosu*[size=s];top=0; ~Stos() void push(eltstosu el); tab[top++]=new EltStosu(el); EltStosu pop(void) ; int empty() return!top; Implementacja Destruktor i pop wymagają więcej uwagi: Stos::~Stos() while(top) delete tab[--top]; delete[] tab; EltStosu Stos::pop() EltStosu res(*tab[--top]); delete tab[top]; return res; 70

Użycie struct Liczba : EltStosu int val; Liczba(int i):val(i) operator int() return val; main() Stos s; s.push(liczba(3)); s.push(liczba(5)); while(!s.empty()) cout << int(s.pop()) << endl ; Niestety...... wprawdzie wydaje się, że to całkiem sprytna implementacja, ale niestety nawet się nie skompiluje. Pierwszy problem stanowi wyrażenie int(s.pop()) s.pop() jest typu EltStosu, a nie Liczba i konwersja do int nie jest dlań zdefiniowana. A może by tak użyć funkcji wirtualnych? Jeszcze jedna heroiczna próba struct EltStosu virtual ~EltStosu() virtual void* operator()()//adres wartości struct Liczba : EltStosu int i; Liczba(int k):i(k) void* operator()()return (void*)&i; //... // konwersja i dereferencja wskaźnika i = *(int*)s.pop()(); // Konwersja Teraz program się kompiluje, ale nie działa :( 71

void* czyli wiem co robię Typ void* oznacza uniwersalny wskaźnik, bez precyzowania typu wskazywanych elementów. Nie można uzyskać elementu wskazywanego przez void*. Można za to dokonywać konwersji między void* a innym wskaźnikiem. Oznacza to powiedzenie kompilatorowi wiem co robię, ale czy rzeczywiście zawsze tak jest? void* przykłady unsigned u = 0xCAFEBABE ; // szesnastkowo unsigned* pu = &u; void* pv = (void*)pu ; char* pc = (char*)pv ; //OK - pierwszy bajt u cout << (*pc == char(0xbe)?"small":"big") << " endian" << endl ; void* przykłady unsigned u = 11; char c = char(0xad); char* pc = &c; void* pv = (void*)pc ; u = *(unsigned*)pv ; cout << hex << u << endl; //??? Problem z push Argument push jest przekazywany przez wartość (chcemy przechowywać kopie obiektów)... ale kopiowanie dokona się przez konstruktor kopiujący z klasy EltStosu. Na stosie będą zatem kopie tylko tych fragmentów obiektów, które pochodzą z EltStosu. 72

Zmiana typu na void push(eltstosu&)... nie poprawia sytuacji. Lepsze push Musimy zatem użyć wskaźników: void push(eltstosu*)tab[top++]=el->kopia(); oraz zdefiniować wirtualną metodę kopiującą: struct EltStosu virtual ~EltStosu() virtual EltStosu* kopia()=0; struct Liczba : EltStosu int i; Liczba(int k):i(k) operator int() return i; EltStosu* kopia() return new Liczba(i); Klasy abstrakcyjne Czasem definiujemy klasę, której obiekty nie będą tworzone. Będą tworzone jedynie obiekty jej podklas. struct EltStosu virtual ~EltStosu() virtual EltStosu* kopia()=0; kopia() jest tzw. metoda czysto wirtualna Co za tym idzie, EltStosu jest klasa abstrakcyjna. Nie można tworzyć obiektów takiej klasy, jedynie jej podklas (o ile nie są abstrakcyjne). 73

Poprawiamy pop Metoda pop też jest zła wynik jest typu EltStosu, zatem znów skopiuje się nieciekawy fragment. Na szczęście możemy ją dość prosto poprawić: EltStosu* pop(void)return tab[--top]; Przy okazji: zdefiniowanie metody kopiuj() jako czysto wirtualnej sprawiło, że EltStosu stał się klasą abstrakcyjną. Kompilator nie pozwoli nam na użycie jej konstruktora, więc błąd w pop() możemy szybko wykryć. Refleksja: gdybyśmy od początku zdefiniowali EltStosu jako klasę abstrakcyjną, kompilator ostrzegłby nas od razu, że pierwotna koncepcja jest błędna. Program główny main() Stos s; s.push(&liczba(3));//push kopiuje s.push(&liczba(5)); while(!s.empty()) Liczba* l; l=(liczba*)s.pop(); cout << int(*l) << endl ; delete l; Podsumowanie Wady: wkładając trzeba dokonać konwersji do podklasy EltStosu, dla każdego typu trzeba zdefiniować podklasę EltStosu, trzeba w niej zdefiniować konstruktor, operator konwersji i metodę kopia(), trzeba dokonywać rzutowań przy pobieraniu (niewygodne, a przede wszystkim niebezpieczne) trzeba pamiętać o usuwaniu pamięci po pobranych obiektach. 74

Wzorce (szablony) Wzorce są narzędziem umożliwiającym parametryzowanie struktur danych. Wzorzec klasy specyfikuje jak można konstruowac poszczególne klasy. Deklarację wzorca poprzedzamy słowem template, po którym w nawiasach kątowych podajemy parametry wzorca. Typowy parametr wzorca deklarujemy używając słowa class a potem nazwy parametru. Parametr faktyczny nie musi być klasą (może być w zasadzie dowolnym typem) Wzorzec stosu template <class T> class Stos T* tab; unsigned size ; Stos(unsigned s=10)tab=new T[s];top=0; ~Stos()delete[] tab; void push(t el)tab[top++]=el; T pop(void) return tab[--top]; int empty() return!top; Używanie szablonów Użycie wzorca polega na zapisaniu jego nazwy wraz z odpowiednimi parametrami (ujętymi w nawiasy kątowe). Takie użycie wzorca może wystąpić wszędzie tam, gdzie może wystąpić typ. main() Stos<int>s; s.push(3); s.push(5); 75

while(!s.empty()) cout << s.pop() << endl ; Parametry rozmiaru Oprócz typów parametrem wzorca może być wartość typu całkowitego (zwykle używana jako rozmiar: template <class T, unsigned size> class Stos T* tab; Stos()tab=new T[size];top=0; ~Stos()delete[] tab; void push(t el)tab[top++]=el; T pop(void) return tab[--top]; int empty() return!top; Stos<int,20> s; Parametry domyślne Podobnie jak dla funkcji, dla wzorców możemy podawać domyślne wartości parametrów, np. template <class T=int, unsigned size=20> class Stos... Przy takiej definicji Stos<> Znaczy tyle co Stos<int,20> s; Wzorce a zgodność typów Dla każdych wartości parametrów tworzona jest nowa klasa. Co za tym idzie, Stos<int,10> 76

oraz Stos<int,20> to dwie niezwiazane ze soba klasy. Szablony funkcji Oprócz wzorców klas można tworzyć również wzorce funkcji globalnych. Oto deklaracja uniwersalnej funkcji maksimum: template<class T> T maks(t a,t b) // NB "max" już jest return (a>b?a:b); i przykłady jej użycia cout <<maks(24,42) << endl; cout <<maks(string("jacek"),string("placek")) <<endl; 77