Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Wielodziedziczenie od środka Konrad Lipiński 07.01.2008.

Podobne prezentacje


Prezentacja na temat: "Wielodziedziczenie od środka Konrad Lipiński 07.01.2008."— Zapis prezentacji:

1 Wielodziedziczenie od środka Konrad Lipiński 07.01.2008

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

3 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++"

4 Implementacja pojedynczego dziedziczenia

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

6 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 */

7 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();

8 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() };

9 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; };

10 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() };

11 Wielodziedziczenie

12 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 =..;

13 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

14 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;

15 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;

16 Dziedziczenie wirtualne

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

18 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; };

19 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

20 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

21 Funkcje wirtualne przy wielodziedziczeniu

22 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; };

23 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

24 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 );

25 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

26 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

27 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; };

28 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(), };

29 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

30 Konstruktory i destruktory

31 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)

32 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

33 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..

34 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ą

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


Pobierz ppt "Wielodziedziczenie od środka Konrad Lipiński 07.01.2008."

Podobne prezentacje


Reklamy Google