====================================================
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()"
====================================================


