#include class A { public: A() : w(1), v(2) {} virtual ~A() {} virtual void foo() { std::cout << "A::foo " << this << " " << w << std::endl; } virtual void quux() = 0; protected: virtual void quuux(int a) { std::cout << "A::quuux " << this << " " << w << " " << a << std::endl; } private: int w, v; }; class B : public A { public: B() { x = 3; } void foo() { std::cout << "B::foo " << this << " " << x << std::endl; } virtual void bar() { std::cout << "B::bar " << this << " " << x << std::endl; } void quux() { std::cout << "B::quux " << this << " " << x << std::endl; } private: int x; }; class C : public A { public: C() { y = 4; } virtual void baz() { std::cout << "C::baz " << this << " " << y << std::endl; foo(); quux(); } private: int y; }; class D : public B, public C { public: D() { z = 5; } void quux() { std::cout << "D::quux " << this << " " << z << std::endl; std::cout << "D::B::A::w = " << *((int *)(((char *)this) + 8)) << std::endl; } virtual void quuuux() { std::cout << "D:quuuuc " << this << std::endl; } private: int z; }; struct AVTable; struct CA { AVTable *vtable; int w; int v; }; struct AVTable { void (*nondelete_dtor)(void *); void (*deleting_dtor)(void *); void (*foo)(void *); void (*quux)(void *); void (*quuux)(int); }; struct BVTable; struct CB { CA a; int x; }; struct BVTable { AVTable a_vtable; void (*bar)(void *); }; struct CC { CA a; int y; }; struct CVTable { AVTable a_vtable; void (*baz)(void *); }; struct CD { CB b; CC c; int z; }; typedef void(*method)(A*, int); int main(int argc, char **argv) { B *b = new B(); D *d = new D(); // static calls d->B::foo(); d->C::foo(); // polymorphic calls ((B*)d)->foo(); ((C*)d)->foo(); // no pointer adjustment d->bar(); // pointer adjustment before calls (equivalent to ((C*)d)->baz()) d->baz(); d->quux(); // error: quuux is protected... //d->B::quuux(); //...but we can get a pointer to it from the vtable method *vtable = *((method **)d); vtable[4]((B*)d, 99); CD *cd = (CD*)d; cd->b.a.vtable->foo(cd); ((BVTable *)(cd->b.a.vtable))->bar(cd); cd->c.a.vtable->foo(&(cd->c)); cd->b.a.vtable->deleting_dtor(cd); //delete d; } /* An instance of A (as seen partway through the construction of an instance of D) 0x00000001004019de 6 A() : w(1), v(2) {} (gdb) print *this $2 = {_vptr.A = 0x1004031b0 , w = 1, v = 2} (gdb) x/4xw this 0x6000394f0: 0x004031b0 0x00000001 0x00000001 0x00000002 (gdb) x/8xg 0x1004031a0 0x1004031a0 <_ZTV1A>: 0x0000000000000000 0x00000001004030d0 0x1004031b0 <_ZTV1A+16>: 0x0000000000000000 0x0000000000000000 0x1004031c0 <_ZTV1A+32>: 0x00000001004018d0 0x0000000100401230 0x1004031d0 <_ZTV1A+48>: 0x0000000100401940 0x0000000000000000 (gdb) x/1i 0x00000001004018d0 0x1004018d0 : push %rbp (gdb) x/1i 0x0000000100401230 0x100401230 <__cxa_pure_virtual>: jmpq *0x6ff2(%rip) (gdb) x/1i 0x0000000100401940 0x100401940 : push %rbp An instance of B (gdb) x/8xw b 0x6000394f0: 0x004031f0 0x00000001 0x00000001 0x00000002 0x600039500: 0x00000003 0x00000006 0x00000053 0x00000000 (gdb) x/8xg 0x1004031e0 0x1004031e0 <_ZTV1B>: 0x0000000000000000 0x00000001004030e0 0x1004031f0 <_ZTV1B+16>: 0x0000000100401c20 0x0000000100401bf0 0x100403200 <_ZTV1B+32>: 0x0000000100401a90 0x0000000100401b00 0x100403210 <_ZTV1B+48>: 0x0000000100401940 0x0000000100401a20 (gdb) x/14i 0x0000000100401c20 0x100401c20 : push %rbp 0x100401c21 : mov %rsp,%rbp 0x100401c24 : sub $0x20,%rsp 0x100401c28 : mov %rcx,0x10(%rbp) 0x100401c2c : lea 0x15bd(%rip),%rdx # 0x1004031f0 <_ZTV1B+16> 0x100401c33 : mov 0x10(%rbp),%rax 0x100401c37 : mov %rdx,(%rax) 0x100401c3a : mov 0x10(%rbp),%rax 0x100401c3e : mov %rax,%rcx 0x100401c41 : callq 0x100401a00 0x100401c46 : nop 0x100401c47 : add $0x20,%rsp 0x100401c4b : pop %rbp 0x100401c4c : retq (gdb) x/13i 0x0000000100401bf0 0x100401bf0 : push %rbp 0x100401bf1 : mov %rsp,%rbp 0x100401bf4 : sub $0x20,%rsp 0x100401bf8 : mov %rcx,0x10(%rbp) 0x100401bfc : mov 0x10(%rbp),%rcx 0x100401c00 : callq 0x100401c20 0x100401c05 : mov $0x18,%edx 0x100401c0a : mov 0x10(%rbp),%rcx 0x100401c0e : callq 0x100401260 <_ZdlPvm> 0x100401c13 : nop 0x100401c14 : add $0x20,%rsp 0x100401c18 : pop %rbp 0x100401c19 : retq (gdb) x/14i 0x100401a00 0x100401a00 : push %rbp 0x100401a01 : mov %rsp,%rbp 0x100401a04 : mov %rcx,0x10(%rbp) 0x100401a08 : lea 0x17a1(%rip),%rdx # 0x1004031b0 <_ZTV1A+16> 0x100401a0f : mov 0x10(%rbp),%rax 0x100401a13 : mov %rdx,(%rax) 0x100401a16 : nop 0x100401a17 : pop %rbp 0x100401a18 : retq (gdb) x/1i 0x0000000100401a90 0x100401a90 : push %rbp (gdb) x/1i 0x0000000100401b00 0x100401b00 : push %rbp (gdb) x/1i 0x0000000100401940 0x100401a20 : push %rbp (gdb) x/12xw d 0x600039510: 0x00403270 0x00000001 0x00000001 0x00000002 0x600039520: 0x00000003 0x00000006 0x004032b0 0x00000001 0x600039530: 0x00000001 0x00000002 0x00000004 0x00000005 (gdb) x/8xg 0x100403260 0x100403260 <_ZTV1D>: 0x0000000000000000 0x0000000100403120 0x100403270 <_ZTV1D+16>: 0x0000000100401ea0 0x0000000100401e70 0x100403280 <_ZTV1D+32>: 0x0000000100401a90 0x0000000100401d70 0x100403290 <_ZTV1D+48>: 0x0000000100401940 0x0000000100401a20 (gdb) x/16xg 0x100403260 0x100403260 <_ZTV1D>: 0x0000000000000000 0x0000000100403120 0x100403270 <_ZTV1D+16>: 0x0000000100401ea0 0x0000000100401e70 0x100403280 <_ZTV1D+32>: 0x0000000100401a90 0x0000000100401d70 0x100403290 <_ZTV1D+48>: 0x0000000100401940 0x0000000100401a20 0x1004032a0 <_ZTV1D+64>: 0xffffffffffffffe8 0x0000000100403120 0x1004032b0 <_ZTV1D+80>: 0x0000000100401f10 0x0000000100401f00 0x1004032c0 <_ZTV1D+96>: 0x00000001004018d0 0x0000000100401ef0 0x1004032d0 <_ZTV1D+112>: 0x0000000100401940 0x0000000100401c80 (gdb) x/1i 0x100401ea0 0x100401ea0 : push %rbp (gdb) x/1i 0x100401e70 0x100401e70 : push %rbp (gdb) x/1i 0x100401a90 0x100401a90 : push %rbp (gdb) x/1i 0x100401d70 0x100401d70 : push %rbp (gdb) x/1i 0x100401940 0x100401940 : push %rbp (gdb) x/1i 0x100401a20 0x100401a20 : push %rbp (gdb) x/3i 0x100401f10 0x100401f10 <_ZThn24_N1DD1Ev>: sub $0x18,%rcx 0x100401f14 <_ZThn24_N1DD1Ev+4>: jmpq 0x100401ea0 0x100401f19 <_ZThn24_N1DD1Ev+9>: nop (gdb) x/3i 0x100401f00 0x100401f00 <_ZThn24_N1DD0Ev>: sub $0x18,%rcx 0x100401f04 <_ZThn24_N1DD0Ev+4>: jmpq 0x100401e70 0x100401f09 <_ZThn24_N1DD0Ev+9>: nop (gdb) x/1i 0x1004018d0 0x1004018d0 : push %rbp (gdb) x/2i 0x100401ef0 0x100401ef0 <_ZThn24_N1D4quuxEv>: sub $0x18,%rcx 0x100401ef4 <_ZThn24_N1D4quuxEv+4>: jmpq 0x100401d70 (gdb) x/2i 0x100401940 0x100401940 : push %rbp 0x100401941 : push %rbx (gdb) x/1i 0x100401c80 0x100401c80 : push %rbp (gdb) x/100i main 0x1004010e0 : push %rbp 0x1004010e1 : push %rbx 0x1004010e2 : sub $0x48,%rsp 0x1004010e6 : lea 0x80(%rsp),%rbp 0x1004010ee : mov %ecx,-0x20(%rbp) 0x1004010f1 : mov %rdx,-0x18(%rbp) 0x1004010f5 : callq 0x100401300 <__main> 0x1004010fa : mov $0x18,%ecx 0x1004010ff : callq 0x100401310 <__wrap__Znwm> 0x100401104 : mov %rax,%rbx 0x100401107 : mov %rbx,%rcx 0x10040110a : callq 0x100401bc0 0x10040110f : mov %rbx,-0x48(%rbp) 0x100401113 : mov $0x30,%ecx 0x100401118 : callq 0x100401310 <__wrap__Znwm> 0x10040111d : mov %rax,%rbx 0x100401120 : mov %rbx,%rcx 0x100401123 : callq 0x100401e80 0x100401128 : mov %rbx,-0x50(%rbp) 0x10040112c : mov -0x50(%rbp),%rax 0x100401130 : mov %rax,%rcx 0x100401133 : callq 0x100401ae0 0x100401138 : mov -0x50(%rbp),%rax 0x10040113c : add $0x18,%rax 0x100401140 : mov %rax,%rcx ---Type to continue, or q to quit--- 0x100401143 : callq 0x100401920 0x100401148 : mov -0x50(%rbp),%rax 0x10040114c : mov (%rax),%rax 0x10040114f : add $0x10,%rax 0x100401153 : mov (%rax),%rax 0x100401156 : mov -0x50(%rbp),%rdx 0x10040115a : mov %rdx,%rcx 0x10040115d : callq *%rax 0x10040115f : cmpq $0x0,-0x50(%rbp) 0x100401164 : cmpq $0x0,-0x50(%rbp) 0x100401169 : je 0x100401175 0x10040116b : mov -0x50(%rbp),%rax 0x10040116f : add $0x18,%rax 0x100401173 : jmp 0x10040117a 0x100401175 : mov $0x0,%eax 0x10040117a : mov (%rax),%rax 0x10040117d : add $0x10,%rax 0x100401181 : mov (%rax),%rax 0x100401184 : cmpq $0x0,-0x50(%rbp) 0x100401189 : je 0x100401195 0x10040118b : mov -0x50(%rbp),%rdx 0x10040118f : add $0x18,%rdx ---Type to continue, or q to quit--- 0x100401193 : jmp 0x10040119a 0x100401195 : mov $0x0,%edx 0x10040119a : mov %rdx,%rcx 0x10040119d : callq *%rax 0x10040119f : mov -0x50(%rbp),%rax 0x1004011a3 : mov (%rax),%rax 0x1004011a6 : add $0x28,%rax 0x1004011aa : mov (%rax),%rax 0x1004011ad : mov -0x50(%rbp),%rdx 0x1004011b1 : mov %rdx,%rcx 0x1004011b4 : callq *%rax 0x1004011b6 : mov -0x50(%rbp),%rax 0x1004011ba : mov 0x18(%rax),%rax 0x1004011be : add $0x28,%rax 0x1004011c2 : mov (%rax),%rax 0x1004011c5 : mov -0x50(%rbp),%rdx 0x1004011c9 : add $0x18,%rdx 0x1004011cd : mov %rdx,%rcx 0x1004011d0 : callq *%rax 0x1004011d2 : mov -0x50(%rbp),%rax 0x1004011d6 : mov (%rax),%rax 0x1004011d9 : add $0x18,%rax 0x1004011dd : mov (%rax),%rax 0x1004011e0 : mov -0x50(%rbp),%rdx ---Type to continue, or q to quit--- 0x1004011e4 : mov %rdx,%rcx 0x1004011e7 : callq *%rax 0x1004011e9 : mov -0x50(%rbp),%rax 0x1004011ed : mov (%rax),%rax 0x1004011f0 : mov %rax,-0x58(%rbp) 0x1004011f4 : mov -0x58(%rbp),%rax 0x1004011f8 : add $0x20,%rax 0x1004011fc : mov (%rax),%rax 0x1004011ff : mov -0x50(%rbp),%rcx 0x100401203 : mov $0x63,%edx 0x100401208 : callq *%rax 0x10040120a : cmpq $0x0,-0x50(%rbp) 0x10040120f : je 0x100401228 0x100401211 : mov -0x50(%rbp),%rax 0x100401215 : mov (%rax),%rax 0x100401218 : add $0x8,%rax 0x10040121c : mov (%rax),%rax 0x10040121f : mov -0x50(%rbp),%rdx 0x100401223 : mov %rdx,%rcx 0x100401226 : callq *%rax 0x100401228 : mov $0x0,%eax 0x10040122d : add $0x48,%rsp 0x100401231 : pop %rbx 0x100401232 : pop %rbp */