CSC448: OO Languages: C++ [3/12] |
==================================================== Object and static calls class A { public: int a; void f(int i) { } }; instance of A: ----------------- | int a; | ----------------- int main() { A* pa; pa->f(2); } implemented as f__F1A(pa,2); ==================================================== Fields class A { int a; void f(int); }; class B : A { int b; void g(int); }; class C : B { int c; void h(int); }; instance of C: ----------------- | int a; | | int b; | | int c; | ----------------- ==================================================== Single inheritance class A { int a; virtual void f(int); virtual void g(int); virtual void h(int); }; class B : A { int b; void g(int); }; class C : B { int c; void h(int); }; instance of C: ----------------- | int a; | vtbl: | vptr .............> ----------------- | int b; | | A::f | | int c; | | B::g | ----------------- | C::h | ----------------- C* pc; pc->g(2); implemented as (*(pc->vptr[1])) ( pc , 2 ); ==================================================== Given a C*, calling a member function of A or C is simple. Calling a member function of B is more complex. class A { ... }; class B { ... }; class C : A , B { ... }; is equivalent to class C : B , A { ... }; C* pc; pc->bf(2); // assume that bf is a member of B // and that C has no member named bf // except the one inherited from B becomes bf__F1B ( (B*)((char*)pc+delta(B)) , 2 ); pc ...................>----------------- | | | A part | | | B::bf's this .........>----------------- | | | B part | | | ----------------- | | | C part | | | ----------------- ==================================================== casting may also involve modifying a pointer C* pc; B* pb; pb = (B*)pc; // pb = (B*)((char*)pc+delta(B)) pb = pc; // ... same pc = (C*)pb; // pc = (C*)((char*)pb-delta(B)) comparisons too! pc == pb; // that is, pc == (C*)pb // pc == (C*)((char*)pb-delta(B)) // equivalently, (B*)pc == pb // (B*)((char*)pc+delta(B)) == pb ==================================================== What about null? C* pc; B* pb; pb = (B*)pc; // pb = (pc==0)?0:(B*)((char*)pc+delta(B)) ==================================================== Virtual functions class A { virtual void f(); }; class B { virtual void f(); virtual void g(); }; class C : A , B { void f(); }; A* pa = new C; B* pb = new C; C* pc = new C; pa->f(); // calls C::f() pb->f(); // calls C::f() pc->f(); // calls C::f() Implementation: ----------------- | | vtbl: | vptr ..........>--------------------- | A part | | C::f | 0 | | | --------------------- ----------------- | | vtbl: | vptr ..........>--------------------- | B part | | C::f | -delta(B) | | | | B::g | 0 | ----------------- --------------------- | | | C part | | | ----------------- pb->f(); // call of C::f: // register vtbl_entry* vt = &pb->vtbl[index(f)]; // (*vt->fct)((B*)((char*)pb+vt->delta)) struct vtbl_entry { void (*fct)(); int delta; }; ==================================================== class W { virtual void f() { ... } virtual void g() { ... } virtual void h() { ... } virtual void k() { ... } }; class AW : virtual W { void g() { ... } }; class BW : virtual W { void f() { ... } }; class CW : AW , BW { void h() { ... } }; CW* pcw = new CW; pcw->f(); // BW::f() pcw->g(); // AW::g() pcw->h(); // CW::h() ((AW*)pcw)->f(); // BW::f(); ----------------- ......... | . | AW part | . | | . ----------------- ......... | . | BW part | . | | . ----------------- . | | . | CW part | . | | vtbl: . ----------------- ------------------------------ ...>| vptr ..........>| BW::f | delta(BW)-delta(W) | | | | AW::g | -delta(W) | | W part | | CW::h | -delta(W) | | | | W::k | 0 | ----------------- ------------------------------ In general, the delta stored with a function pointer in a vtbl is the delta of the class defining the function minus the delta of the class for which the vtbl is constructed. ==================================================== A virtual base class is inherited only once. What does this code do without virtual inheritance? class A { int fa; }; class B : public virtual A { void g() { fa++; } void init() { fa=0; } }; class C : public virtual A { void h() { cout << fa; } void init() { fa=0; } }; class D : public B, public C { }; D d; d.B::init(); d.C::init(); d.g(); d.h(); ==================================================== The complexity of MI -- static checks class A { int g() { return 1; } int f() { return 2; } }; class B { int g() { return 3; } int f() { return 4; } }; class C : public A, public B { int g() { return 5; } }; C c; c.f(); // Compile time error, ambiguous c.g(); // returns 5 ==================================================== class Top { virtual void f() { cout << "Top::f()"; } }; class Left : public virtual Top { void g() { f(); } }; class Right : public virtual Top { virtual void f() { cout << "Right::f()"; } }; class Bottom : public Left, public Right { }; Bottom b; b.g(); // prints "Right::f()" // with non-virtual inheritance, prints "Top::f()" ====================================================