Listy powiązane zorientowane obiektowo

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

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

wykład IV uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C, a C++. wykład IV dr Jarosław Mederski Spis Język C++ - wstęp

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

Wyjątki (exceptions)

Wstęp do Programowania 2

TEMAT : KLASY POLIMORFIZM

Plik klasy. h deklaracje klas

PARADYGMATY PROGRAMOWANIA Wykład 4

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

Mechanizm dziedziczenia

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

Języki Programowania. Prowadząca: dr inż. Hanna Zbroszczyk. tel: Konsultacje: piątek:

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

Techniki programowania INP001002Wl rok akademicki 2017/18 semestr letni. Wykład 4. Karol Tarnowski A-1 p.

2.4 Dziedziczenie. 2.4 Dziedziczenie Przykłady programowania w C - kurs podstawowy

Programowanie - wykład 4

TEMAT : KLASY DZIEDZICZENIE

Programowanie i struktury danych

C++ - [4-7] Polimorfizm

dr inż. Jarosław Forenc

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

Programowanie obiektowe

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

Jak napisać listę jednokierunkową?

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

Programowanie obiektowe

Projektowanie klas c.d. Projektowanie klas przykład

1. Pierwszy program. Kompilator ignoruje komentarze; zadaniem komentarza jest bowiem wyjaśnienie programu człowiekowi.

Polimorfizm w pigułce

Programowanie obiektowe i C++ dla matematyków

Programowanie i struktury danych

Projektowanie obiektowe. Roman Simiński Wzorce projektowe Wybrane wzorce strukturalne

Wykład 5: Klasy cz. 3

Język C++ wykład VIII

Jak Windows zarządza pamięcią?

Owad():waga(1),jadowitosc(false) {cout<<"konstruktor domyslny owada\n";}

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

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

Materiał uzupełniający do ćwiczen z przedmiotu: Programowanie w C ++ - ćwiczenia na wskaźnikach

Laboratorium z przedmiotu Programowanie obiektowe - zestaw 04

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

Zaawansowane programowanie w języku C++ Programowanie obiektowe

Podstawy informatyki. Elektrotechnika I rok. Język C++ Operacje na danych - wskaźniki Instrukcja do ćwiczenia

Zaawansowane programowanie w języku C++ Klasy w C++

Wykład 4: Klasy i Metody

Szablony funkcji i klas (templates)

Opis zagadnieo 1-3. Iteracja, rekurencja i ich realizacja

Programowanie obiektowe w języku C++ Zarządzanie procesami. dr inż. Jarosław Forenc. Przeładowanie (przeciążanie) operatorów

wykład V uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C++ klasy i obiekty wykład V dr Jarosław Mederski Spis Język C++ - klasy

Wstęp do programowania

Język C++ wykład VII. uzupełnienie notatek: dr Jerzy Białkowski. Programowanie C/C++ Język C++ wykład VII. dr Jarosław Mederski. Spis.

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

Zajęcia nr 5 Algorytmy i wskaźniki. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Programowanie obiektowe w języku

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Aplikacje w środowisku Java

Wstęp do programowania obiektowego, wykład 7

Programowanie komputerowe. Zajęcia 1

Podstawy programowania w języku C++ Zadania - dziedziczenie i polimorfizm

Programowanie obiektowe i zdarzeniowe

Zajęcia nr 2 Programowanie strukturalne. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

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

Oracle PL/SQL. Paweł Rajba.

Zasady programowania Dokumentacja

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

Zaawansowane programowanie w C++ (PCP)

Aplikacje w środowisku Java

Programowanie Obiektowe Ćwiczenie 4

Laboratorium 1 - Programowanie proceduralne i obiektowe

Algorytmy i Struktury Danych. Anna Paszyńska

STL: Lekcja 1&2. Filozofia STL

Wstęp do wiadomości teoretycznych (nie, nie jest to masło maślane ani wstęp, wstępów proszę cierpliwie czytać)

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

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

Podstawy programowania skrót z wykładów:

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

Programowanie obiektowe

Rozdział 4 KLASY, OBIEKTY, METODY

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:

Programowanie obiektowe w C++ Wykład 12

Paradygmaty programowania. Paradygmaty programowania

Szablony klas, zastosowanie szablonów w programach

Wstęp do informatyki- wykład 12 Funkcje (przekazywanie parametrów przez wartość i zmienną)

Mechanizm dziedziczenia

Programowanie w języku C++

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

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Laboratorium 3. Instrukcje wyboru

Programowanie i struktury danych. Wykład 4 Dr Piotr Cybula

Programowanie obiektowe w języku C++ dr inż. Jarosław Forenc

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 12

Wykład 8: klasy cz. 4

Technologie cyfrowe semestr letni 2018/2019

Polimorfizm, metody wirtualne i klasy abstrakcyjne

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

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

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie obiektowe, wykład nr 6. Klasy i obiekty

Wstęp do programowania

Transkrypt:

Listy powiązane zorientowane obiektowo Aby zilustrować potęgę polimorfizmu, przeanalizujmy zorientowaną obiektowo listę powiązaną. Jak zapewne wiesz, lista powiązana jest strukturą danych, zaprojektowaną do przechowywania nieokreślonej liczby obiektów. Istnieje oczywiście możliwość przechowywania obiektów w tablicy, lecz tablice muszą posiadać określony rozmiar. Jeżeli zatem nie wiesz dokładnie, ilu obiektów będziesz potrzebował do stworzenia całego projektu, korzystanie z tablicy może nie być najlepszym rozwiązaniem. Zakładając zbyt dużą tablicę tracisz pamięć, zakładając zbyt małą ryzykujesz, iż nie zdoła ona pomieścić wszystkich elementów. Właśnie z tych powodów warto skorzystać z list powiązanych. Projektowanie listy powiązanej Lista powiązana jest zazwyczaj implementowana jako łańcuch węzłów. Każdy węzeł (ang, node) wskazuje na obiekt (Twoje ) oraz na następny węzeł listy. Gdy łańcuch nie zawiera już więcej węzłów, wówczas węzeł wskazuje na zero rysunek 3.1. Zero Rys. 3.1. Lista powiązana Aby każdy węzeł posiadał określoną funkcję, należy utworzyć trzy typy: LinkedList (ListaPowiązana), TailNode (OgonWęzłów) i InternalNode (Wewnętrzny). Typ LinkedList udostępnia klientowi dostęp do wpisu listy, TailNode wskazuje na koniec listy, a InternalNode przechowuje bieżące dane. Wspólne cechy trzech typów możemy zamieścić w klasie bazowej Node, zawierającej dwie metody: Insert() i Show(). Insert() umieszcza obiekt danych w liście, natomiast Show() wyświetla wartość danych. Zachodzącą pomiędzy obiektami relację przedstawia rysunek 3.2 +Insert(): Node +Show(): void ListaPowiązana -mynext: Node Wewnętrzny -mynext(): Node -mydata: Data Ogonów Rys. 3.2. Hierarchia dziedziczenia węzła 1

Część I Programowanie zorientowane obiektowo Jesse Liberty C++. Księga eksperta. Zarówno węzeł LinkedList, jak i InternalNode posiadają zmienną obiektu Node, nazywaną mynext. Wskaźnik ten używany jest do znajdywania następnego węzła w liście. Jak zapewne zauważyłeś, omawiana lista jest listą jednokierunkową oznacza to, że każdy węzeł może wskazywać jedynie węzeł kolejny (nie ma możliwości wskazania węzła poprzedniego). Spróbujmy teraz utworzyć klasę Data. Klasa ta będzie potrzebować jakiejś wartości (np. typu integer) i metody pozwalającej na porównanie dwóch obiektów (w naszym przypadku porównanie będzie polegało na określeniu, która wartość jest większa). Chcielibyśmy również, aby obiekt mógł wyświetlać swoją zawartość. W omawianym projekcie powiedzieliśmy, że LinkedList jest specjalnym rodzajem węzła, odpowiedzialnym za przedstawianie interfejsu listy klientowi. Czy przeczy to zasadzie, że dziedziczenie reprezentowane jest przez relację jest? Niezupełnie LinkedList jest specjalnym typem węzła zaznaczającym początek listy. W rzeczywistości konstrukcja listy jest wirtualna (abstrakcyjna). Dlatego też, obiekt LinkedList przedstawia faktycznie dostęp do listy. Implementacja listy powiązanej Tworzenie węzła LinkedList pociąga za sobą tworzenie obiektu TailNode: LinkedList::LinkedList() nextnode = new TailNode; Dlatego nawet pusta lista zawiera dwa obiekty: LinkedList i TailNode nie ma natomiast obiektu InternalNode, przechowującego dane (rysunek 3.3). OgonWęzłów ListaPowiązana Rys. 3.3. Pusta lista Po umieszczeniu danych w węźle LinkedList, węzeł natychmiast wystawia wskaźnik dla następnego węzła: Node * LinkedList::Insert(Data * thedata) 2

Wywołanie funkcji Insert() jest informacją dla węzła TailNode o konieczności dodania nowego węzła do listy. Nowy węzeł jest wstawiany na przedostatniej pozycji listy (przed TailNode). Każdy nowy obiekt umieszczany na przedostatnim miejscu listy musi być, zgodnie z definicją, najmniejszym obiektem (w sensie porównywania reprezentowanej przez niego wartości). Umieszczenie nowego obiektu na liście polega na utworzeniu węzła InternalNode, którego konstruktor posiada dwa argumenty: wskaźnik do danych oraz do następnego węzła (w naszym przypadku drugim argumentem jest wskaźnik do TailNode). Node *TailNode::Insert(Data * thedata) InternalNode * datanode = new InternalNode (thedata, this); Nowo utworzony InternalNode zawiera wskaźnik do danych i do TailNode. TailNode po utworzeniu węzła zwraca do niego wskaźnik, zatem w omawianym przypadku zwraca on do węzła LinkedList wskaźnik do InternalNode. LinkedList przypisuje własny wskaźnik następnego węzła do zwróconej wartości z nextnode->insert(). Cała ta sytuacja została przedstawiona na rysunku 3.4. WęzłełWewnętrzny OgonWęzłów ListaPowiązana Rys. 3.4. Po dodaniu nowego węzła Wskaźnik określa miejsce przesłania danych w obecnej sytuacji, po dodaniu nowego elementu, nie będzie to już TailNode, lecz InternalNode. InternalNode, pobierając obiekt Data, porównuje swoje własne dane z danymi nowego węzła: Node * InternalNode::Insert(Data *thedata) int result = mydata->compare(*thedata); 3

Część I Programowanie zorientowane obiektowo Jesse Liberty C++. Księga eksperta. Nowy obiekt musi być najmniejszym istniejących węzłów. Jeżeli spełnia to założenie, to InternalNode przesyła obiekt Data do następnego węzła listy: case ksmaller: Wartość danych każdego wewnętrznego węzła jest sprawdzana. Jeżeli nowe dane są najmniejszymi danymi listy, węzeł może przejść w TailNode i zostać umieszczony jako ostatni węzeł w liście. W przeciwnym wypadku, gdy InternalNode zawiera dane mniejsze niż nowy obiekt, wówczas właśnie ten węzeł wewnętrzny jest odpowiedzialny za umieszczenie nowych danych w liście. W tym przypadku InternalNode (oznaczmy go chwilowo numerem 1) tworzy nowy węzeł (2), który ma za zadanie wskazywać obiekt, który został utworzony (czyli węzeł 1). Obrazując tą sytuację, nowy węzeł zostaje utworzony przed aktualnym obiektem InternalNode. Wskaźnik do nowego węzła jest zwracany przez InternalNode, tak aby za pomocą wywołania Insert() można było przyłączyć nowy obiekt do listy. case ksame: // przepada case klarger: // nowe dane umieszczam przed sobą InternalNode * datanode = new InternalNode(theData, this); W przykładzie przedstawiona jest sytuacja, w której obiekt zawierający tę samą wartość co obiekt aktualny, traktowany jest tak, jak gdyby zawierał wartość większą (z dwu obiektów zawierających tę samą wartość wcześniej w liście występuje ten, który został później do niej dopisany). Oczywiście w łatwy sposób można zrezygnować z takiego rozwiązania, zmieniając odpowiedni kod implementacji. Po umieszczeniu obiektu w liście, program pyta użytkownika o podanie nowych danych na końcu użytkownik musi określić moment zakończenia wprowadzania nowych elementów. Mając gotową listę możemy spowodować jej wyświetlenie: virtual void Show() nextnode->show() W przypadku pustej listy wystąpi wskazanie na TailNode; funkcja Show() nic nie wyświetli. Jednak, gdy lista nie będzie pusta, wskazany zostanie węzeł wewnętrzny. Działanie funkcji Show() przedstawione jest w poniższym przykładzie: virtual void Show() mydata->show(); nextnode->show(); Każdy wewnętrzny węzeł wyświetla wówczas swoje dane i odsyła funkcję Show() do następnego węzła, z którym jest powiązany. Procedurę wyświetlania kończy osiągnięcie przez funkcję obiektu TailNode. Kiedy przychodzi pora na usunięcie listy, należy wywołać destruktor, usuwający kolejny węzeł: ~LinkedList() delete nextnode; 4

W ten sposób kolejno usuwa się wszystkie węzły listy, aż do napotkania obiektu TailNode występuje tu efekt domino : skasowanie jednego węzła powoduje skasowanie kolejnego. Nie ma przy tym potrzeby pamiętania ilości węzłów umieszczonych w liście. Wszystkie wyżej omówione zagadnienia, zostały przedstawione w listingu 3.1 Listing 3.1. Lista powiązana zorientowana obiektowo #include <iostream> using namespace std; enum ksmaller, klarger, ksame; class Data Data(int val):datavalue(val) virtual ~Data() virtual int Compare(const Data &); virtual void Show()cout << datavalue << endl; int datavalue; ; int Data::Compare(const Data & theotherdata) if (datavalue < theotherdata.datavalue) return ksmaller; if (datavalue > theotherdata.datavalue) return klarger; else return ksame; class Node // abstrakcyjny typ danych Node() virtual ~Node() virtual Node * Insert (Data * thedata) = 0; virtual void Show() = 0; ; class InternalNode: public Node InternalNode(Data * thedata, Node * next); ~InternalNode() delete nextnode; delete mydata; virtual Node * Insert(Data * thedata); virtual void Show() mydata->show(); nextnode->show(); Data * mydata; Node * nextnode; ; InternalNode::InternalNode(Data * thedata, Node * next): mydata(thedata), nextnode(next) 5

Część I Programowanie zorientowane obiektowo Jesse Liberty C++. Księga eksperta. Node * InternalNode::Insert(Data *thedata) int result = mydata->compare(*thedata); switch(result) case ksame: // przepada case klarger: // nowe dane umieszczam przed sobą InternalNode * datanode = new InternalNode(theData, this); case ksmaller: class TailNode: public Node TailNode() ~TailNode() virtual Node * Insert(Data * thedata); virtual void Show() ; Node *TailNode::Insert(Data * thedata) InternalNode * datanode = new InternalNode (thedata, this); class LinkedList: public Node LinkedList(); ~LinkedList() delete nextnode; virtual Node * Insert(Data * thedata); virtual void Show() nextnode->show(); Node *nextnode; ; LinkedList::LinkedList() nextnode = new TailNode; Node * LinkedList::Insert(Data * thedata) int main() 6

Data * pdata; int val; LinkedList l1; for (;;) cout << "Jaka wartosc chcesz dodac do listy?? (wpisz 0 aby zakonczyc): "; cin >> val; if (!val) break; pdata = new Data(val); l1.insert(pdata); cout << "\n\n"; l1.show(); cout << "\n\n"; return 0; Każdy obiekt jest odpowiedzialny tylko za jeden dany obszar, a wszystkie węzły traktowane są przez niego polimorficznie. Dzięki wyszczególnieniu obiektów LinkedList, InternalNode oraz TailNode możemy utworzyć bardzo scentralizowaną aplikację, której kod jest znacznie łatwiejszy do modyfikacji. Najważniejszą częścią kodu, z perspektywy zrozumienia polimorfizmu, jest sposób wywołania węzła: nextnode->insert(). Każdy obiekt (za wyjątkiem TailNode), wie tylko tyle, że posiada wskaźnik do kolejnego węzła; nie wie natomiast, czy jest to TailNode, czy InternalNode. Można więc powiedzieć, że obiekt wywołujący nie wie, co wywołuje, lecz wie tylko o samym wydarzeniu. Procedura wyświetlania zawartości listy polega natomiast na wywołaniu węzła, który wyświetla swoją zawartość i przekazuje wywołanie do następnego węzła. Proces kończy się na osiągnięciu przez funkcję obiektu TailNode. 7