Wielodziedziczenie od środka Konrad Lipiński 07.01.2008.

Slides:



Advertisements
Podobne prezentacje
C++ wykład 9 ( ) Szablony.
Advertisements

C++ wykład 2 ( ) Klasy i obiekty.
C++ wykład 4 ( ) Przeciążanie operatorów.
Deklaracje i definicje klas w C++ Składowe, pola, metody Konstruktory
Programowanie obiektowe
Wskaźniki repetytorium Wskaźniki int Y = 1, X = 2; X = 5; int *p = &X; Y X p 4 4 p = &Y; *p = 4; 5.
Klasy i obiekty.
Metody wirtualne.
Wzorce.
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
Sposoby obejścia dziedziczenia
Implementacja ekstensji klasy
Szablony (wzorce) Przykład 1: Szablon klasy -
OOPC++ - wstêp, klasy1 Klasy Do struktury można dołączyć operacje działające na jej polach. struct date { int day, month, year; void set (int d, int m,
Licznik template<class Count_Type> class Count { public:
DZIEDZICZENIE · klasy bazowe i klasy pochodne WyświetlAutora( ) Autor
C++ wykład 2 ( ) Klasy i obiekty.
Typy pochodne 1 Często dogodnie jest wprowadzić nowy typ, który jest podobny do istniejącego, niemniej jednak różny. Niech T będzie pewnym typem. Możemy.
Mechanizmy dziedziczenia
Języki programowania obiektowego
Czytanie, pisanie i rysowanie – cd.. Jeszcze jeden strumyk PrintStream działa jak PrintWriter, ale: Używa domyślnego (systemowego) kodowania Nie wyrzuca.
Techniki programowania gier
T: Różnice pomiędzy programowaniem strukturalnym a obiektowym
Programowanie obiektowe w C++
Programowanie obiektowe III rok EiT
Programowanie obiektowe III rok EiT
Java – coś na temat Klas Piotr Rosik
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.
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 9 ( )
Programowanie w języku C++
Kurs języka C++ – wykład 5 ( )
Dobry kod OO Jeżeli zapytamy statystycznego programistę z czym kojarzy mu się dobry kod OO to najprawdopodobniej będzie mówił o wzorcach projektowych.
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
K URS JĘZYKA C++ – WYKŁAD 10 ( ) Szablony.
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
Wydział Elektroniki Kierunek: AiR Zaawansowane metody programowania Wykład 5.
Kurs języka C++ – wykład 4 ( )
K URS JĘZYKA C++ – WYKŁAD 2 ( ) Klasy i obiekty.
Konstruktory i Destruktory. Konstruktor Konstruktor — co to? Konstruktor — co to? jest metodą służącą do inicjowania obiektów danej klasy jest metodą.
Paweł Starzyk Obiektowe metody projektowania systemów
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 Operatory rzutowania Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały.
K URS JĘZYKA C++ – WYKŁAD 3 ( ) Przenoszenie Składowe statyczne Funkcje wbudowane Argumenty domyślne.
Inżynieria oprogramowania Wzorce konstrukcyjne WWW: Jacek Matulewski Instytut Fizyki, UMK.
Programowanie Obiektowe – Wykład 6
Kurs języka C++ – wykład 3 ( )
Klasy, pola, obiekty, metody. Modyfikatory dostępu, hermetyzacja
(według:
Delegaty Delegat to obiekt „wiedzący”, jak wywołać metodę.
Programowanie Obiektowe – Wykład 2
Kurs języka C++ – wykład 4 ( )
Programowanie obiektowe
Założenia projektowe Javy
PGO Dziedziczenie Michail Mokkas.
Zapis prezentacji:

Wielodziedziczenie od środka Konrad Lipiński

Nie interesuje nas: Inżynieria oprogramowania Debata wielodziedziczenie vs standardowe dziedziczenie

Będziemy mówić o: Implementacji wielodziedziczenia Podejściu stosowanym tradycyjnie w C++ Problemach wynikających z implementacji Oprzemy się na książce S. Lippmana "Model obiektu w C++"

Implementacja pojedynczego dziedziczenia

Implementacja dziedziczenia Podejście tradycyjne: tablice funkcji wirtualnych (vtbl) Dynamiczna informacja o typie: type_info if (circle *c = dynamic_cast (some_shape)) { // use circle }

Tablice funkcji wirtualnych typedef.. Vtbl; // start of class class Child : public Parent { Vtbl *vtbl; // Parent members // Child members }; Child::vtbl == Parent::vtbl + Child::virtual_methods; // end of class class Child : public Parent { // Parent members Vtbl *vtbl; // Child members }; /* vtbl after Child if Parent is not polymorphic */

Dynamiczna informacja o typie / konstrukcja vtbl typedef... type_info; typedef struct { type_info *tinfo; // virtual method addresses // every virtual function is granted // a compile-time index within the table } Vtbl; // pure virtual function indicator // throws an exception if called void pure_virtual_called();

Funkcje wirtualne – nadklasa class Point { virtual ~Point(); virtual Point &mult( float ) = 0; float x() const { return _x; } virtual float y() const { return _y; } virtual float z() const { return _z; } protected: Point( float x = 0.0 ); float _x; }; struct Point_Layout { float _x; Vtbl *vtbl_Point = { typeinfo_Point, Point::~Point(), pure_virtual_called(), Point::y(), Point::z() };

Funkcje wirtualne – I podklasa class Point2d : public Point { Point2d( float x = 0.0, float y = 0.0 ) : Point( x ), _y( y ) {} ~Point2d(); // overridden virtuals Point2d &mult( float ); float y() const { return _y; } protected: float _y; }; struct Point2d_Layout { Point_subobject { float _x; Vtbl *vtbl_Point2d = { typeinfo_Point2d, Point2d::~Point2d(), Point2d::mult(), Point2d::y(), Point::z() }; float _y; };

Funkcje wirtualne – II podklasa class Point3d : public Point2d { Point3d( float x = 0.0, float y = 0.0, float z = 0.0 ) : Point2d( x, y ), _z( z ) {} ~Point3d(); // overridden virtuals Point3d &mult( float ); float z() const { return _z; } // additional virtuals virtual float sum() const; protected: float _z; }; struct Point3d_Layout { Point2d_subobject { Point_subobject { float _x; Vtbl *vtbl_Point3d; float _y; }; float _z; }; Point3d_Layout::vtbl_Point3d = { typeinfo_Point3d, Point3d::~Point3d(), Point3d::mult(), Point2d::y(), Point3d::z(), Point3d::sum() };

Wielodziedziczenie

class Derived : public Base1, public Base2 { // Base1 members Vtbl *vtbl_Base1; //+ Derived::virtual_methods // Base2 members Vtbl *vtbl_Base2; //+ Derived::virtual_methods // Derived members }; Derived *derived =..; Base1 *base1 =..; Base2 *base2 =..;

Wielodziedziczenie: problemy Rzutowanie Wielokrotne występowanie tej samej klasy podstawowej class B : public Twice; class C : public Twice; class D : public B, public C; Funkcje wirtualne Konstruktory i destruktory

Rzutowanie C++: derived = base1; base1 = derived; derived = base2; base2 = derived; Compiled Pseudo-C++: derived = base1; base1 = derived; derived = base2 ? base2 - sizeof Base1 : 0; base2 = derived ? derived +sizeof Base1 : 0;

Wielokrotne podklasy Jawna kwalifikacja podklasy Twice::doSth(); D *d =...; d->doSth();// wrong d->B::doSth();// OK Dziedziczenie wirtualne class VB : public virtual Once; class VC : public virtual Once; class VD : public VB, public VC;

Dziedziczenie wirtualne

Nadklasa występuje w obiekcie tylko raz Once::doSth(); VD *vd =...; vd->doSth();// OK Wirtualna nadklasa nie ma stałej pozycji w obiekcie polimorficznym

Przykład implementacji: wskaźnik do nadklasy wirtualnej class VB { float data_VB; Once *p_once; Vtbl *vtbl_VB; Once once_subobject; }; class VC { float data_VC; Once *p_once; Vtbl *vtbl_VC; Once once_subobject; }; struct VD_Layout { VB_subobject { float data_VB; Once *p_once_VB; Vtbl *vtbl_VB; // + VD::virtuals }; VC_subobject { float data_VC; Once *p_once_VC; Vtbl *vtbl_VC; // + VD::virtuals }; float data_VD; Once once_subobject; };

Wskaźnik do nadklasy wirtualnej - problemy Każdy poziom dziedziczenia wirtualnego dodaje jedne poziom pośredniości przez wskaźnik Jeśli zależy nam na stałym czasie dostępu, możemy skopiować do każdej klasy wskaźniki do wszystkich (nie tylko bezpośrednich) nadklas wirtualnych Duże wymagania pamięciowe

Inna implementacja: offsety do nadklas wirtualnych.... w tablicy funkcji wirtualnych typedef struct { // virtual base class offsets type_info *tinfo; // virtual method addresses } Vtbl; Brak narzutu na rozmiar obiektów Jedna dodatkowa dereferencja wskaźnika

Funkcje wirtualne przy wielodziedziczeniu

Funkcje wirtualne class Base1 { Base1(); virtual ~Base1(); virtual void speak(); virtual Base1 *clone() const; protected: float data_Base1; }; class Base2 { Base2(); virtual ~Base2(); virtual void mumble(); virtual Base2 *clone() const; protected: float data_Base2; }; class Derived : public Base1, public Base2 { Derived(); virtual ~Derived(); virtual Derived *clone() const; protected: float data_Derived; };

Funkcje wirtualne a wielodziedziczenie Manipulacja wskaźnikiem this w czasie działania programu Base2 *pb2 = new Derived; // must launch Derived::~Derived delete pb2; Wygenerowanie jednej vtbl dla każdej nadklasy wirtualnej danej klasy Ta sama klasa może mieć kilka różnych vtbl w różnych kontekstach w hierarchii dziedziczenia

Przesuwanie this: offsety Osobny offset dla wszystkich metod w tabeli funkcji wirtualnych Dwukrotny wzrost rozmiaru Vtbl Wolniejsze wywołanie wirtualne // zamiast pb2->vtbl[1] ( pb2 ); // mamy pb2->vtbl[1].addr ( pb2 + pb2->vtbl[1].off );

Przesuwanie this: thunk Thunk = reverse (Knuth) thunk_dtor_Base2_Derived: this += sizeof(Base1); Derived::~Derived(); Efektywne na poziomie assemblera Przezroczyste z punktu widzenia mechanizmu wywołania wirtualnego

Przesuwanie this: podwajanie funkcji Typowa funkcja wirtualna nie przekracza ośmiu linijek Dla małej funkcji generujemy dwie instancje kodu, z których jedna przesuwa this a druga nie Dla dużej funkcji definiujemy kilka punktów wejściowych

Vtbl przy wielodziedziczeniu struct Base1_Layout { float data_Base1; Vtbl *vtbl_Base1 = { typeinfo_Base1, Base1::~Base1(), Base1::speak(), Base1::clone() }; struct Base2_Layout { float data_Base2; Vtbl *vtbl_Base2 = { typeinfo_Base2, Base2::~Base2(), Base2::mumble(), Base2::clone() }; struct Derived_Layout { Base1_subobject { float data_Base1; Vtbl *vtbl_Base1 = { typeinfo_Derived, Derived::~Derived(), Base1::speak(), Derived::clone(), Base2::mumble() // this! }; Base2_subobject { float data_Base2; Vtbl *vtbl_Base2 = { typeinfo_Derived, Derived::~Derived(), // this! Base2::mumble(), Derived ::clone() // this! }; float data_Derived; };

Vtbl a nadklasa wirtualna class Point2d { Point2d( float = 0.0, float = 0.0 ); virtual ~Point2d(); virtual void mumble(); virtual void z(); protected: float _x, _y; }; class Point3d : public virtual Point2d { Point3d( float = 0.0, float = 0.0, float = 0.0 ); ~Point3d(); float z(); protected: float _z; }; struct Point3d_Layout { float _z; Vtbl *vtbl_Point3d = { 8, // Point2d offset typeinfo_Point3d, Point3d::~Point3d(), Point3d::mumble(), Point3d::z(), }; Point2d_subobject { float _x, _y; Vtbl *vtbl_Point2d = { typeinfo_Point3d, Point3d::~Point3d(), Point3d::mumble(), Point3d::z(), };

Dane w nadklasach wirtualnych.. Nastręczają problemów w skomplikowanych hierarchiach z dziedziczeniem wirtualnym Autor uznał że algorytmy tworzenia Vtbl w tym przypadku są zbyt ezoteryczne by je omawiać.. Posłuchamy go. Autor odradza deklarowanie danych niestatycznych w nadklasach wirtualnych

Konstruktory i destruktory

Dziedziczenie a konstruktory Ustawienie vtbl we wszystkich konstruktorach Brak semantyki kopiowania bitowego Synteza / wzmocnienie konstruktorów (w tym również domyślnych i kopiujących)

Kaskadowe konstruktory.... Mogą zawierać wywołania funkcji wirtualnych Przez czas wykonywania konstruktora A::A(...) vtbl musi być ustawiony na podstawowy A::vtbl (musimy mieć do czynienia z klasą A, nie podklasą).. Wymagają osobnego ustawienia vtbl dla każdego wywoływanego konstruktora

Dziedziczenie a destruktory Przy wykonywaniu destruktora nadklasy musimy korzystać z vtbl dla nadklasy Kaskadowe ustawianie vtbl Wzmocnienie destruktorów Odwrotna kolejność względem konstruktorów Nadklasy wirtualne..

Konstruktory/destruktory a nadklasy wirtualne Podobiekty nadklas wirtualnych muszą być inicjalizowane/niszczone tylko raz, przez najmłodszą w hierarchii dziedziczenia klasę Dwa warianty konstruktorów/destruktorów lub parametr bool is_most_derived dla każdej klasy z wirtualną nadklasą

The End Complete Dziękuję i zapraszam do dyskusji!