Обратите внимание, что все это определяется реализацией!
Хотя некоторые реализации могут использовать функцию батута, это не единственный способ сделать это, и не то, как gcc реализует это
С gcc, если вы запустите код, который вы разместили, вы получите это:
A::sayHello: 1
Поскольку вместо сохранения адреса функции-батута указатель на функцию-член для виртуальной функции сохраняется как { vtable offset + 1, this-ptr offset }
, и то, что вы печатаете, является первым словом этого. (Подробнее см. http://sourcery.mentor.com/public/cxx-abi/abi.html#member-pointers)).
В этом случае sayHello
является единственной записью vtable, и поэтому смещение vtable равно 0. 1
добавляется, чтобы пометить этот указатель на функцию-член как виртуальную функцию-член.
Если вы проверяете сборку на предмет выполнения вызовов указателя на функцию-член при компиляции с g ++, вы получите некоторые инструкции на сайте вызова, которые вычисляют адрес вызываемой функции, если это виртуальный указатель на функцию-член:
(a->*pointer_to_function)(); //print "A"
Load the first word of the member function pointer into rax:
4006df: 48 8b 45 c0 mov -0x40(%rbp),%rax
Check the lower bit:
4006e3: 83 e0 01 and $0x1,%eax
4006e6: 84 c0 test %al,%al
If non-virtual skip the next bit:
4006e8: 74 1b je 400705 <main+0x81>
virtual case, load the this pointer offset and add the this pointer (&a):
4006ea: 48 8b 45 c8 mov -0x38(%rbp),%rax
4006ee: 48 03 45 e0 add -0x20(%rbp),%rax
rax is now the real 'this' ptr. dereference to get the vtable ptr:
4006f2: 48 8b 10 mov (%rax),%rdx
Load the vtable offset and subtract the flag:
4006f5: 48 8b 45 c0 mov -0x40(%rbp),%rax
4006f9: 48 83 e8 01 sub $0x1,%rax
Add the vtable offset to the addr of the first vtable entry (rdx):
4006fd: 48 01 d0 add %rdx,%rax
Dereference that vtable entry to get a real function pointer:
400700: 48 8b 00 mov (%rax),%rax
Skip the next line:
400703: eb 04 jmp 400709 <main+0x85>
non-virt case, load the function address from the member function pointer:
400705: 48 8b 45 c0 mov -0x40(%rbp),%rax
Load the 'this' pointer offset:
400709: 48 8b 55 c8 mov -0x38(%rbp),%rdx
Add the actual 'this' pointer:
40070d: 48 03 55 e0 add -0x20(%rbp),%rdx
And finally call the function:
400711: 48 89 d7 mov %rdx,%rdi
400714: ff d0 callq *%rax