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

Podobne dokumenty
PARADYGMATY PROGRAMOWANIA Wykład 4

Szablony klas, zastosowanie szablonów w programach

Polimorfizm, metody wirtualne i klasy abstrakcyjne

Dziedziczenie jednobazowe, poliformizm

Szablony funkcji i klas (templates)

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

Zaawansowane programowanie w języku C++ Programowanie obiektowe

Wykład 9: Polimorfizm i klasy wirtualne

Język C++ Programowanie obiektowe

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

C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm POLIMORFIZM

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

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

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

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

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

Zaawansowane programowanie w C++ (PCP)

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

Wykład 8: klasy cz. 4

Wprowadzenie do programowanie obiektowego w języku C++

Lab 9 Podstawy Programowania

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

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

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

TEMAT : KLASY DZIEDZICZENIE

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

C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie C++ - DZIEDZICZENIE.

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016

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

Programowanie obiektowe w języku

Stos liczb całkowitych

C++ - [4-7] Polimorfizm

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

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

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

Programowanie Obiektowe i C++

Plik klasy. h deklaracje klas

Podstawy Programowania Obiektowego

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

Programowanie obiektowe i zdarzeniowe

Wstęp do Programowania 2

Kurs WWW. Paweł Rajba.

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

Zaawansowane programowanie w C++ (PCP)

Instrukcja do pracowni specjalistycznej z przedmiotu. Obiektowe programowanie aplikacji

Klasa dziedzicząca posiada wszystkie cechy klasy bazowej (plus swoje własne) dodawanie nowego kodu bez edycji (i ewentualnego wprowadzania

PARADYGMATY PROGRAMOWANIA Wykład 2

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

Podstawy programowania obiektowego

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

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

Typy zmiennych proste i złożone. Programowanie komputerów. Tablica. Złożone typy zmiennych. Klasa. Struktura

Wykład 9: Metody wirtualne i polimorfizm

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

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

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

Wykład 5: Klasy cz. 3

Zaawansowane programowanie w C++ (PCP)

Wykład 4: Klasy i Metody

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

Dziedziczenie. Tomasz Borzyszkowski

Dziedziczenie. Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut.

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

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 28 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27

Programowanie w języku C++

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

Materiały do zajęć VII

Wstęp do programowania

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

Programowanie obiektowe w C++ Wykład 12

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

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

Programowanie obiektowe - 1.

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

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Klasa, metody, rozwijanie w linii

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

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

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

Polimorfizm. dr Jarosław Skaruz

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 13 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 30

Dziedziczenie jednobazowe, poliformizm, tablice wskaźników na obiekty

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

Programowanie obiektowe. Dr hab. Inż. Marta Gładysiewicz-Kudrawiec Pokój 229 A1 Operatory new delete pliki-odczyt

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

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

Szablony funkcji i szablony klas

Funkcje wirtualne. Wskaźniki do klas pochodnych są podstawą dla funkcji wirtualnych i polimorfizmu dynamicznego.

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

Informatyka I. Dziedziczenie. Nadpisanie metod. Klasy abstrakcyjne. Wskaźnik this. Metody i pola statyczne. dr inż. Andrzej Czerepicki

Języki i techniki programowania Ćwiczenia 4 Wzorce

Wykład 3 Składnia języka C# (cz. 2)

Pola i metody statyczne. Klasy zawierające pola i metody statyczne

Interfejsy i klasy wewnętrzne

PROE wykład 3 klasa string, przeciążanie funkcji, operatory. dr inż. Jacek Naruniec

> C++ dziedziczenie. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki

Języki i techniki programowania Ćwiczenia 3 Dziedziczenie

Dokumentacja do API Javy.

Klasa, metody, rozwijanie w linii

Transkrypt:

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

Co dają wzorce klas? Pisząc programy często korzystamy z abstrakcyjnych typów danych, takich jak stos, kolejka czy drzewo. Implementacje takich typów mogą być prawie identyczne, na przykład klasy lista_liczb i lista_znaków mogą różnić się tylko typem elementu przechowywanego na liście. Wzorzec klasy to sposób na napisanie uogólnionej. sparametryzowanej klasy klasy której parametrem będzie typ, bądź inna klasa. Można napisać wzorzec listy, a potem w zależności od tego czego aktualnie potrzebujemy zadeklarować listę znaków, bądź listę figur. Wzorce są doskonalszym i wygodniejszym sposobem (od stosowania preprocesora) tworzenia rodzin typów i funkcji. Wzorce nazywane są również szablonami (ang. templates). Wzorce klas jak deklarować? template <class T> // wzorzec, którego argumentem jest typ T class stos // wzorzec klasy stos T* v; // początek stosu T* p; // koniec stosu int rozm; // pojemność stosu stos (int r) v = p = new T[rozm=r];} // konstruktor z argumentem: // rozmiar stosu ~stos () delete[]v;} // destruktor void wstaw(t a) *p++ = a;} // wstaw na stos T zdejmij() return *--p;} // zdejmij ze stosu int rozmiar() const return p-v;} // ile elementów typu T jest na stosie 2

Wzorce klas jak deklarować? template <class T> class stos // deklarujemy wzorzec, // którego argumentem jest typ T // wzorzec klasy stos Typu (klasy) T można używać do końca deklaracji klasy stos tak jak każdego innego dostępnego typu lub klasy. W zakresie wzorca template<t> stos<t> używanie pełnej nazwy typu stos<t> jest nadmiarowe zarówno przy definicji metod wewnątrz klasy jak i poza nią, wystarczy stos zarówno dla określenia klasy jak i nazw konstruktorów i destruktora. Wzorce klas jak deklarować? Mając wzorzec klasy stos można deklarować stosy różnych elementów przekazując typ elementu jako aktualny parametr wzorca. Składnia nazwy typu wywiedzionego ze wzorca jest następująca: nazwa_klasy_wzorca<argument_wzorca> Nazwa klasy stosu liczb: stos<int> Nazwa klasy stosu wskaźników do figur: stos<figura *> 3

Wzorce klas Deklaracja: stos<int> liczby(100); to deklaracja obiektu o nazwie liczby, należącego do klasy stos<int>, oraz wywołanie konstruktora stos<int>(100). Nazwy klasy utworzonej ze wzorca można używać tak samo jak nazwy każdej innej klasy, różnica to inna składnia nazwy. stos<figura*> spf(200); // stos wskaźników do figur zdolny // pomieścić 200 wskaźników stos<punkt> sp(400); // stos punktów o pojemności 400 void f(stos<complex> &sc) // funkcja f, której argumentem jest // referencja do stosu liczb zespolonych sc.wstaw(complex(1,2)); // wstaw do stosu przekazanego jako argument // funkcji liczbę zespoloną complex z = 2.5 * sc.zdejmij(); // zdejm liczbe ze stosu, // pomnóż ją i przypisz stos<int> *p=0; // deklaracja wskaźnika do // stosu liczb całkowitych p=new stos<int>(800); // konstrukcja stosu 800 liczb całkowitych for (int i=0; i<400; i++) // 400 razy p->wstaw(i); // wstaw liczbe i do stosu liczb sp.wstaw(punkt(i,i+400)); // i punkt do stosu punktów } delete p; // destrukcja stosu liczb } 4

Wzorce Kompilator sprawdza poprawność wzorca w momencie jego użycia, a więc błędy w samej deklaracji wzorca mogą pozostać niezauważone aż do momentu próby wykorzystania wzorca. Poprawna kompilacja pliku zawierającego wzorzec nie oznacza że wzorzec nie zawiera błędów. Częstą praktyką jest najpierw uruchomienie konkretnej klasy, np. stos_znaków, a potem przekształcenie jej w klasę ogólną - wzorzec stos<t>. Wzorce W wcześniejszej wersji wzorca wszystkie metody są inline zdefiniowano je wewnątrz deklaracji klasy. Można we wzorcu nie definiować metod: template <class T> class stos T* v; // początek stosu T* p; // koniec stosu int rozm; // pojemność stosu stos (int r); // deklaracja: konstruktor z argumentem: rozmiar stosu ~stos (); void wstaw(t a); // deklaracja: wstaw na stos T zdejmij(); // deklaracja: zdejmij ze stosu int rozmiar(); // deklaracja: ile elementów typu T jest na stosie 5

Wzorce Jeżeli metody wzorca definiujemy poza definicją klasy wzorca to musimy użyć dla każdej z metod słowa kluczowego template: // definicja metody wstaw template<class T> void stos<t>::wstaw(t a) *p++ = a; // konstruktor template<class T> stos<t>::stos(int r) v = p = new T[rozm=r]; Przypomnienie: W zakresie wzorca Wzorce template<t> stos<t> używanie pełnej nazwy typu stos<t> jest nadmiarowe zarówno przy definicji metod wewnątrz klasy jak i poza nią. Wystarczy stos zarówno dla określenia klasy jak i nazw konstruktora i destruktora ( <T> jest domyślne). Poniższy wzorzec jest błędny: // template<class T> // stos<t>::stos<t>(int r) // to jest traktowane jako błąd, // // powinno być stos<t>:: stos(int r) // // v = p = new T[rozm=r]; // 6

Rozbudowywanie klas-wzorców Wzorca który jest już napisany i wykorzystywany nie należy modyfikować modyfikacje te będą dotyczyły wszystkich klas stworzonych w oparciu o ten wzorzec. Gdy dodamy zmienne klasowe to powiększą się obiekty wszystkich tych klas wywiedzionych ze wzorca. Gdy zmienimy definicje metod to zmiany będą dotyczyły wsystkich klas wywiedzionych ze wzorca. Zatem, zamiast modyfikacji wzorca danej klasy należy utworzyć wzorzec klasy pochodnej, o nowych właściwościach. Rozbudowywanie klas-wzorców Np.: potrzebujemy stosu łańcuchów z możliwością zapisu i odczytu do pliku template<class T> class stos_plik: public stos<t> char * nazwa_pliku; /* konstruktor, parametry: rozmiar i nazwa pliku */ stos(int rozmiar, char * nazwa = NULL) :stos<t>(rozmiar) // konstrukcja rodzica // tutaj, lub za pomocą listy inicjalzacyjnej zachowaj nazwę pliku } void zapisz_stos(); void wczytaj_stos(); 7

Wzorzec szczegółowy Jeżeli wzorzec działa niepoprawnie dla jakiegoś szczególnego parametru, to można zdefiniować inną wersję wzorca dla konkretnego parametru. Np. klasa która służy do porównywania elementów danego typu: template<class T> class porównywacz// wzorzec ogólny static mniejszy(t &a, T &b) return a<b; } Powyższe jest poprawne dla typów takich, jak int czy char. Dla łańcuchów (char *) porównywane by były nie łańcuchy, ale ich adresy, Wzorzec szczegółowy Dla łańcuchów (char *) porównywane by były nie łańcuchy, ale ich adresy, więc definiujemy szczególną postać wzorca klasy porównywacz dla łańcuchów: class porównywacz<char *> // wzorzec szczegółowy static mniejszy(const char * a, const char * b) return strcmp(a, b)<0; } Kompilator wykorzysta szczególną postać wzorca, jeżeli w miejscu gdzie będzie potrzebna, będzie widoczna (czyli zadeklarowana wcześniej). W przeciwnym przypadku zostanie rozwinięty wzorzec ogólny. 8

Argumenty wzorca Argumentów wzorca może być wiele, oprócz klas i typów mogą to być napisy, nazwy funkcji lub wyrażenia stałe. Np. wzorzec bufora, którego parametrem będzie rozmiar: template<class T, int rozm> class bufor T w[rozm]; //... } taki wzorzec bufora wykorzystujemy np. tak: bufor<figura, 250> tbf; bufor<char,100> tbc; // deklaracja obiektu f będącego // buforem na 250 figur // bufor na 100 znaków Wzorce Dwa typy wygenerowane ze wspólnego wzorca są identyczne jeżeli identyczne są argumenty wzorca, w przeciwnym przypadku są różne i nie wiąże ich pokrewieństwo. Na przykład dla następujących deklaracji tylko obiekty tbc0 i tbc1 należą do tej samej klasy (klasy bufor<char, 100>) pozostałe obiekty do obiekty różnych klas. bufor<char,100> tbc0; bufor<figura, 250> tbf0; bufor<char,100> tbc1; bufor<figura, 300> tbf1; 9

Wzorce funkcji template <class T> void zamień(t &x, T &y) T t=x; x=y; y=t; } // jesteśmy poza deklaracją klasy // nie metoda, a funkcja int a=7,b=8; zamień(a,b); // kompilator rozwinie wzorzec //(jeżeli jest widoczny) Wzorce funkcji - przykład napisać rodzinę funkcji zwiększających wartość swojego pierwszego argumentu aktualnego o wartość drugiego argumentu (oba to typy liczbowe) template <class t> void zwieksz(t &i, double d) // zadzaiala dla wszystkich typów liczbowych // ale jak ktos wywola zwieksz(1, 1) i+=t(d); // to będą 2 automatyczne konwersje // nieekologiczne --- marnotrawstwo czasu template <class t, class d> void zwieksz_szybciej (t &i, const d delta) // const nie zaszkodzi // a może się przyda i+=t(delta); 10

Wzorce funkcji - przykład napisać rodzinę funkcji zwiększających wartość swojego pierwszego argumentu aktualnego o wartość drugiego argumentu (oba to typy liczbowe), lub o 1 gdy nie podano drugiego argumentu. // template <class t, class d> // void zwieksz_1 (t &i, const d delta=1) // Pułapka: po napotkaniu wywołania zwieksz_1(20.30, 1); kompilator nie ma podstaw do określenia typu d! Wzorce funkcji - przykład napisać rodzinę funkcji zwiększających wartość swojego pierwszego argumentu aktualnego o wartość drugiego argumentu (oba to typy liczbowe), lub o 1 gdy nie podano drugiego argumentu. template <class t, class d> void zwieksz_1(t &i, const d delta) i+=t(delta); template <class t> void zwieksz_1(t &i) i+=t(1); 11

Metody wirtualne Potrzeba metod wirtualnych Przy dziedziczeniu w C++ dla wskaźników i referencji dozwolona jest konwersja, ale: przez taki wskaźnik lub referencję można odwoływać się jedynie do danych zadeklarowanych w klasie bazowej, oraz jedynie do metod klasy bazowej na podstawie klasy wskaźnika/referencji kompilator zdecyduje o wywołaniu metody kl. bazowej nazwet jeżeli obiekt jest klasy potomnej. 12

class punkt int x,y; void pokaz(); //rysuje punkt void ukryj(); class okrag: public punkt int r; void pokaz(); //rysuje punkt void ukryj(); okrag o; punkt &rp=o; rp.pokaz(); //punkt::pokaz Potrzeba metod wirtualnych okrag o; punkt &rp=o; rp.pokaz(); // niech wywoła się okrag::pokaz jak to zrealizować? 13

class punkt int x,y; char klasa; void pokaz(); //rysuje punkt punkt(int x, int y) :x(x), y(y), klasa= p ; } Rozwiązanie niedoskonałe Wadliwe class okrag: public punkt int r; void pokaz(); //rysuje punkt okrag(int x, int y, int r) :punkt(x,y), r(r) klasa= o ; } okrag o; punkt &rp=o; if (rp.klasa== p ) rp.punkt::pokaz(); else rp.okrag::pokaz(); Metody wirtualne Jeżeli zadeklarujemy metodę jako wirtualną to kompilator uzupełni obiekty o pole determinujące klasę obiektu i przy wywoływaniu wybranych przez nas metod wywoła metodę z właściwej klasy. void virtual punkt::ukryj(); Metodę (albo operator) wystarczy raz zadeklarować jako wirtualny, w klasach pochodnych możemy, ale nie musimy używać słowa kl. virtual. 14

Metody wirtualne class punkt int x,y; class okrag: public punkt int r; void virtual pokaz(); void virtual ukryj(); void pokaz(); // virtual void ukryj(); // virtual Metody wirtualne - działanie Do pierwszej klasy w której w hierarchii klas pojawi się metoda wirtualna dodane zostanie dodatkowe niejawne pole adres tablicy metod wirtualnych. zwiększy się rozmiar obiektów tej klasy. Dla obiektu, którego klasy nie można jednoznacznie określić na etapie kompilacji, odwołania do metody, bądź metod zadeklarowanych jako wirtualne będą się odbywały pośrednio poprzez tablicę metod wirtualnych będzie to działało wolniej niż odwołanie bezpośrednie, metody wirtualne nie będą rozwijane inline, będzie to działało szybciej, niż gdybyśmy taką sztuczkę robili ręcznie, kompilator nie pomyli się (człowiek wiadomo). 15

Metody wirtualne - działanie Odwołania przez wskaźnik i referencje będą pośrednie Odwołania przez kwalifikację obiektem będą bezpośrednie a więc szybsze, metody (nawet zadeklarowane z virtual) mogą być rozwijane inline. Uwaga: metody klasy mogą zostać odziedziczone i aktywowane na rzecz obiektu klasy pochodnej, a więc odwołania do wirtualnych metod danej klasy z innych metod tej klasy będą też pośrednie! class punkt int x,y; void virtual pokaz(); void virtual ukryj(); void przesun(int dx, int dy) ukryj(); // wirtualna w punkt x+=dx; y+=dy; pokaz(); // wirtualna w punkt } class okrag: public punkt int r; void pokaz(); void ukryj(); okrag o; punkt &rp=o; rp.pokaz(); //okrag::pokaz rp.przesun(); //punkt::przesun wywoła //okrag::pokaz i okrag::ukyj!!! 16

Klasa polimorficzna klasa polimorficzna to taka w której występuje przynajmniej jedna metoda wirtualna Przykład korzyści z polimorfizmu: deklarujemy listę przechowującą wskaźniki do punktów (klasa polimorficzna) - na liście umieszczać punkty okręgi i inne figury. przez wskaźniki możemy pokazać wszystkie figury (wywołując metodę wirtualną pokaz() pośrednio), możemy też przesuwać figury wyw. się niewirtualna metoda przesuń, ona wywoła właściwe, bo wirtualne pokaz i ukryj. Wczesne i późne wiązanie Wczesne wiązanie: gdy metoda nie jest wirtualna lub jest wirtualna ale można określić z której klasy ma pochodzić to nazwa metody jest kojarzona z jej kodem (wywołanie metody albo nawet rozwinięcie inline) już na etapie kompilacji/linkowania. Późne wiązanie decyzja co do wyboru klasy z zakresu której metodę wykonać, zostaje podjęta podczas biegu programu. 17

Wczesne i późne wiązanie Metody nie-wirtualne zawsze wczesne wiązanie. Zadeklarowanie metody jako wirtualnej nie wyklucza jej wczesnego wiązania, nastąpi ono, gdy: jawnie (operatorem zakresu) podamy o którą klasę nam chodzi, wywołamy metodę bezpośrednio na rzecz obiektu (nie przez wskaźnik lub referencję). Metody wirtualne zaleta: ogromna łatwość rozbudowy programu, Pisząc kod możemy wykorzystywać metody których jeszcze nie napisano! Nie musimy powielać takiego samego kodu w metodach różnych klas (vide przesun()). Nie grozi nam uzupełnienie już gotowego kodu o nowe błędy. 18

Konstruktory i destruktory Konstruktor nie może być wirtualny (dlaczego?) Destruktor może i czasami powinien być virtual (dlaczego?) Uwaga: Gdy w jakiejś klasie zadeklarujemy destruktor jako wirtualny, to w klasach pochodnych destruktory też będą wirtualne (mimo że ich nazwy w klasach pochodnych będą inne). Static i virtual Metoda statyczna nie może być wirtualna (dlaczego?). 19

Dziedziczenie metod wirtualnych meoda wirtualna może zostać odziedziczona przez klasę pochodną może zostać przedefiniowana, w jej ciele możemy wywołać metodę wirtualną klasy bazowej. np.: void okrag::pokaz() punkt::pokaz(); // narysuj środek okręgu //narysuj okrąg } Przeciążanie a wirtualność wirtualność dotyczy tylko tej metody/operatora która została w danej klasie lub przodku zadeklarowana jako virtual, inne metody (o innych parametrach) są zwykłymi metodami/operatorami. np. metoda nie wirtualna: void punkt::pokaz(char * opis)... 20

Zaprzyjaźnianie a wirtualność Wirtualność jest niezależna od zaprzyjaźniania. Zaprzyjaźnianie nie jest przechodnie, Zaprzyjaźnianie dotyczy tylko tej metody (klasa::metoda) która została zaprzyjaźniona, Metoda przedefiniowana w klasie pochodnej, wirtualna czy nie, nie będzie automatycznie zaprzyjaźniona. Widoczność metod wirtualnych Widoczność jest rozstrzygana na etapie kompilacji zatem decyduje typ wskaźnika/referencji. np., przyjmijmy, że wszystkie składowe klasy okrąg sa prywatne: okrag o; punkt &rp=o; rp.pokaz(); // OK. dlaczego? 21

Klasa abstrakcyjna Klasa abstrakcyjna, to klasa, która nie zawiera żadnych obiektów. Klasa abstrakcyjna służy do definiowania interfejsu/cech wspólnych rodziny innych klas (jej potomków) np. klasa abstrakcyjna figura liczba Dziedziczenie klas abstrakcyjnych Metoda czysto wirtualna W C++ klasa abstrakcyjna to taka, która zawiera przynajmniej jedną metodę czysto wirtualną tj. taką która jest wirtualna, i nie ma zdefiniowanego ciała. void virtual figura::rysuj()=0; 22

Koniec 23