通过vptr调用C++虚函数:如何调用第二个虚函数?
Hey there! Let's break down your code and question step by step so you grasp exactly how that pointer manipulation works, and how to call the second virtual function.
First: What's happening in your existing code?
Your line void(*firstfunc)() = (void(*)(void))(*(int*)*(int*)p); is manually traversing the virtual function table (VTABLE) via the virtual pointer (vptr). Here's a play-by-play:
pis abase*pointing to aderivedobject. For classes with virtual functions, the first piece of memory in the object is the vptr—a pointer to the class's VTABLE.(int*)p: Cast the object pointer toint*so we can read the first 4 bytes (assuming 32-bit architecture; for 64-bit, you'd uselong long*oruintptr_tto match pointer size) which holds the vptr address.*(int*)p: Dereference this to get the actual value of the vptr—this is the starting address of thederivedclass's VTABLE.(int*)*(int*)p: Cast the VTABLE address toint*so we can index into the array of function pointers stored in the VTABLE.*(int*)*(int*)p: Dereference this to get the first function pointer in the VTABLE.(void(*)(void)): Cast that raw address to a function pointer type that matches the signature of your virtual functions (no parameters, no return value).- Calling
firstfunc()runs that first virtual function, which isderived::fun_2()—because the VTABLE order follows the order of virtual function declarations in the base class:fun_2is first, thenfun_3, thenfun_4.
How to call the second virtual function?
To call the second virtual function (fun_3), you just need to access the second element in the VTABLE array. That means adding an offset of 1 to the VTABLE pointer (since each element is a function pointer).
Here's the modified code for the second function:
int main() { base *p; derived obj1; p = &obj1; // Call first virtual function (fun_2) void(*firstfunc)() = (void(*)(void))(*(int*)*(int*)p); firstfunc(); // Call second virtual function (fun_3) void(*secondfunc)() = (void(*)(void))(*((int*)*(int*)p + 1)); secondfunc(); }
When you run this, the output will be:
derived-2
base-3
Because derived doesn't override fun_3, so the VTABLE uses the base class's implementation.
Important Notes
- This is undefined behavior according to the C++ standard. The standard doesn't specify how virtual functions are implemented—compilers can use different VTABLE layouts, add extra data, or even omit vptr/VTABLE entirely in some cases (like when a class has no virtual functions or is optimized).
- The code assumes 32-bit pointers (using
int*). For 64-bit systems, replaceint*withlong long*oruintptr_t(from<cstdint>) to avoid pointer truncation. - This is purely for learning purposes! Never write code like this in production—use normal virtual function calls (
p->fun_3()) instead, which are safe, readable, and compiler-friendly.
内容的提问来源于stack exchange,提问作者Blood-HaZaRd

