Metody wirtualne.

Slides:



Advertisements
Podobne prezentacje
Tablice 1. Deklaracja tablicy
Advertisements

C++ wykład 2 ( ) Klasy i obiekty.
C++ wykład 4 ( ) Przeciążanie operatorów.
Język C/C++ Funkcje.
Programowanie obiektowe
Deklaracje i definicje klas w C++ Składowe, pola, metody Konstruktory
Programowanie obiektowe
Programowanie obiektowe
Wzorce.
Prowadzący: mgr inż. Elżbieta Majka
Static, const, volatile.
Dziedziczenie. Po co nam dziedziczenie? class osoba { char * imie, char * imie, * nazwisko; * nazwisko;public: void wypisz_imie(); void wypisz_imie();
Generics w .NET 2.0 Łukasz Rzeszot.
Programowanie w środowisku sieciowym
Programowanie obiektowe w Javie
DZIEDZICZENIE · klasy bazowe i klasy pochodne WyświetlAutora( ) Autor
Struktury.
Tablice.
Dziedziczenie i jego rodzaje
C++ wykład 6 ( ) Polimorfizm.
C++ wykład 2 ( ) Klasy i obiekty.
Zasady zaliczenia Warunki uzyskania zaliczenia:
Wykład 1: Wskaźniki Podstawy programowania Programowanie w C
Podstawy informatyki 2013/2014
Podstawy programowania
Informatyka I Wykład 10 WSKAŹNIKI I ADRESY Jerzy F. Kotowski.
Programowanie obiektowe III rok EiT
Programowanie obiektowe III rok EiT dr inż. Jerzy Kotowski Wykład XIII.
Programowanie obiektowe III rok EiT
Andrzej Repak Nr albumu
Java – coś na temat Klas Piotr Rosik
Dziedziczenie Maciek Mięczakowski
Inicjalizacja i sprzątanie
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Programowanie obiektowe Wykład 6 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14 Dariusz Wardowski.
Podstawy informatyki 2013/2014
Programowanie obiektowe 2013/2014
Prasek Aneta, Skiba Katarzyna. Funkcje stałe const to takie funkcje, które nie mogą modyfikować stanu obiektu. Oznacza to, że funkcja stała nie może zmieniać.
Kurs języka C++ – wykład 3 ( )
Kurs języka C++ – wykład 9 ( )
Programowanie w języku C++
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
Programowanie strukturalne i obiektowe C++
Kurs języka C++ – wykład 4 ( )
K URS JĘZYKA C++ – WYKŁAD 2 ( ) Klasy i obiekty.
K URS JĘZYKA C++ – WYKŁAD 6 ( ) Polimorfizm.
Klasy ( uzupełnienie ). Definicja klasy Klasa jest zbiorem logicznie powiązanych danych i funkcji, przeznaczonych do realizacji konkretnego zadania; Zamknięcie.
Programowanie obiektowe Wykład 9 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/15 Dariusz Wardowski.
Dziedziczenie wielobazowe. dana klasa może mieć kilka bezpośrednich klas bazowych: dana klasa może mieć kilka bezpośrednich klas bazowych: kolorpołożenie.
Programowanie Zaawansowane
Dziedziczenie Wykład 7 Dziedziczenie sekwencyjne
Wykład 4 Klasa Vec, której konstruktory alokują pamięć dla obiektów 1.Przykład definicji klasy Vec 2.Definicje konstruktorów i destruktora 3.Definicja.
PO13-1 / 19 Wykład 13 Wyjątki i ich zgłaszanie Wyłapywanie wyjątków Obsługa wyjątków Wykorzystanie polimorfizmu Filtrowanie wyjątków Błędy w konstruktorach.
Wykład 5 Klasa Vec i jej operatory 1.Kategorie operatorów 2.Operatory ogólne - przykłady 3.Operatory specjalne [ ], ( ) oraz –> 4.Operatory new i delete.
Wykład 8 Polimorfizm 1.Funkcje polimorficzne 2.Czyste funkcje wirtualne i klasy abstrakcyjne PO8-1 / 38.
Partnerstwo dla Przyszłości 1 Lekcja 28 Dziedziczenie i rodzaje dziedziczenia.
Podstawy informatyki Funkcje Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego Matuszyka Podstawy.
K URS JĘZYKA C++ – WYKŁAD 3 ( ) Przenoszenie Składowe statyczne Funkcje wbudowane Argumenty domyślne.
Programowanie Obiektowe – Wykład 6
Kurs języka C++ – wykład 3 ( )
Klasy, pola, obiekty, metody. Modyfikatory dostępu, hermetyzacja
(według:
Programowanie Obiektowe – Wykład 2
Kurs języka C++ – wykład 4 ( )
Założenia projektowe Javy
Język C++ Typy Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego.
PGO Dziedziczenie Michail Mokkas.
Zapis prezentacji:

Metody wirtualne

Dlaczego metody wirtualne? W C++ dla wskaźników i referencji dozwolona jest konwersja potomna → bazowa. 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.

class punkt { int x,y; public: void pokaz(); //rysuje punkt void ukryj(); }; class okrag: public punkt int r; okrag o; punkt &rp=o; rp.pokaz(); //punkt::pokaz

Dlaczego metody wirtualne? okrag o; punkt &rp=o; rp.pokaz(); // niech wywoła się okrag::pokaz jak to zrealizować?

class punkt { int x,y; public: 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; public: 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();

void virtual punkt::ukryj(); 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.

Metody wirtualne class punkt { int x,y; public: void virtual pokaz(); void virtual ukryj(); }; class okrag: public punkt { int r; public: 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).

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; public: 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; public: void pokaz(); void ukryj(); }; okrag o; punkt &rp=o; rp.pokaz(); //okrag::pokaz rp.przesun(); //punkt::przesun wywoła //okrag::pokaz i okrag::ukyj !!!

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.

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.

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?).

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){...};

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?

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;

RTTI Ponieważ wskaźnikowi na przodka można przypisać adres potomka to typ wskaźnika nie determinuje klasy do której należy obiekt wskazywany. Czasami w trakcie działania programu pojawia się potrzeba sprawdzenia do jakiej klasy dany obiekt należy. Jeżeli wskaźnik bądź referencja dotyczy klasy polimorficznej to obiekt zawiera pole umożliwiające identyfikację klasy (wskaźnik do tablicy metod wirtualnych), na jego podstawie mechanizm RTTI pozwala sprawdzać typy w trakcie biegu programu. Jeżeli wskaźnik, bądź referencja dotyczy typu podstawowego bądź klasy nie-polimorficznej to typ określany jest na podstawie typu wskaźnika/referencji a nie rzeczywistego obiektu/zmiennej — bo nie ma danych by to zrobić inaczej.

type_info typeid(arg) RTTI RTTI — RunTime Type Information operator typeid type_info typeid(arg) arg: typ, klasa, zmienna bądź obiekt

RTTI class type_info { // tu prywatny konstruktor kopiujący i operator przypisania // nie można z zewnątrz tworzyć kopii obiektów tej klasy public: virtual ~type_info(); bool operator==(const type_info& rhs) const; bool operator!=(const type_info& rhs) const; bool before(const type_info& rhs) const; const char* name() const; };

RTTI class A { virtual void a(){}; }; class B:public A {}; class C:public B {}; A a, *pa; C c; pa=&c; typeid(C)==typeid(pa) // 0 typeid(a)==typeid(*pa) // 0 typeid(c)==typeid(*pa) // 1 typeid(B).name() // B typeid(pa).name() // A * typeid(*pa).name() // C typeid(A).before(typeid(*pa)) // 1 typeid(B).before(typeid(*pa)) // 1 typeid(C).before(typeid(*pa)) // 0 typeid(C).before(typeid(a)) // 0

operatory rzutowania dla zastąpienia rzutowania w stylu języka C *_cast operatory rzutowania dla zastąpienia rzutowania w stylu języka C static_cast < type-id > ( wyrażenie ) dynamic_cast < type-id > ( wyrażenie ) reinterpret_cast < type-id > ( wyrażenie ) const_cast < type-id > ( wyrażenie ) to 4 operatory i 4 słowa kluczowe C++ zaprojektowane by umożliwić większą kontrolę na poziomie kompilacji i wykonania kodu nad (podatnymi na błędy) rzutowaniami pozwalają wyrazić intencję programisty

static_cast static_cast < type-id > ( wyrażenie ) rzutownie oparte na typach znanych podczas kompilacji podobnie niebezpiczne jak rzutowanie C: (type-id ) wyrażenie używać ostożnie działa szybko nie dopuszcza się modyfikacji kwalifikacji const i volatile wyrażenia

static_cast static_cast < type-id > ( wyrażenie ) class A {}; class B:public A { int method(); }; int fun(A * pa) static_cast<B*>(pa) -> method() // miejmy nadzieję, że pa wskazuje na B }

dynamic_cast dynamic_cast < type-id > ( wyrażenie ) rzutowanie oparte o RTTI, używane ze wskaźnikami i referencjami dla wskaźników zwraca NULL, jeśli type-id nie jest ani typu wyrażenia ani jego rodzica dla referencji w ww. przypadku zgłaszany jest wyjątek bezpieczne, mniej szybkie nie dopuszcza się modyfikacji kwalifikacji const i volatile wyrażenia

dynamic_cast dynamic_cast < type-id > ( wyrażenie ) class A {}; class B:public A { }; int fun() A *pa, *aptr=new A; B *pb, *bptr=new B; ... pa=dynamic_cast<A*>(bptr); // OK pb=dynamic_cast<B*>(aptr); // NULL !!! pb=dynamic_cast<B*>(pa); // OK }

reinterpret_cast reinterpret_cast < type-id > ( wyrażenie ) rzutownie oparte na typach znanych podczas kompilacji używane dla arytmetyki adresów (wskaźników), do konwersji typu „w górę” używaj dla wskaźników i liczb całkowitych (wyraź swoją intencję) niech Twój szef myśli że jesteś guru programowania w C++ ;) CLASS *ptr; ... unsigned int adress=reinterpret_cast<unsigned int>(ptr);

const_cast const_cast < type-id > ( wyrażenie ) rzutownie oparte na typach znanych podczas kompilacji używaj dla wskaźników i referencji używaj dla usunięcia kwalifikacji cost i/lub volatile wyrażenia class CLASS { int member; int CLASS::constmethod() const const_cast<CLASS *>(this) -> member++; // const_cast<int>(member)++; ERROR }

mutable słowo kluczowe mutable sprawia, że nie-stała i nie-statyczna zmienna klasowa pozostanie nie-stała w stałych metodach klasy class CLASS { mutable int member; int CLASS::constmethod() const member++; // bo member jest mutable }