pFun = ( Fun )*( ( int* ) * ( int* )( &b ) + i )

#include <iostream>
using namespace std;

calss A{

virtual void g()
{
cout << "A::g" << endl;
}
private:
virtual void f()
{
cout << "A::f" << endl;
}
};
class B : public A {
void g()
{
cout << "B::g" << endl;
}
virtual void h()
{
cout << "B::h" << endl;
}
};
typedef void( *Fun )( void );

int main()
{
B b;
Fun pFun;
for(int i = 0 ; i < 3; i++)
{
pFun = ( Fun )*( ( int* ) * ( int* )( &b ) + i );
pFun();
}
}
输出结果:
B::g
A::f
B::h

typedef void( *Fun )( void ); //Yes, Fun is defined as a function pointer that has no parameters and returns void type

*( (int*) * (int* )( &b) + i) this paragraph,
(int* )* is equivalent to not performing any operation, so it is equivalent to
*( (int* )( &b) + i)
Here first take the address of b, and then convert the address to int*, then +i is pointer arithmetic, which is in b The length of an int is added to the address, and the last * is the solution pointer, so what is returned at the end of this paragraph is "the address of b + the value of the length of i int". The
first (Fun) is to force the " address of b + The value of " i int length " is converted to a "function pointer with no parameters and return void type", so pFun is a function pointer , and the position it points to is from the address of b at the beginning. Each loop adds an int length

and then Let's open it, the address of b, b is a type B, the first function of type B is g() , and the address of pFun in the first loop is the address of b, and b has no attributes (private or shared variables), so The address of b is the address of the first function g in b, so pFun() in the first loop is equivalent to calling B::g

(Fun )*( (int*) * (int* )( &b) + i) ; Here *( (int*) * (int* )( &b) + i) The first * is to de-pointer the above result, that is, take the address of b + i int length, And convert it to Fun type, that is, a function pointer that has no parameters and returns void type, so the final result is a function pointer. The address pointed to by this pointer is

Then we look at the loop. In the loop, the pFun variable is assigned 3 times, each of which is a function pointer.
Because there is a virtual function in the B type, the address of b points to the vtbl of b (if you don’t know This, your interview will be useless), vtbl can be seen as an array of function pointers, each element is an int length, in vtbl B::g, A::f, B::h is in the order above Arranged, so the first loop points to B::g, then the next two times point to A::f and B::h.

As for why it is arranged in this order, it is because of the order of declaration, first is the parent class The virtual functions are placed in vtbl according to the order of their lives, and then the subclasses are placed in, so the order is: A::h, A::f (this is the declaration order of the parent class) There is only B:: H is newly declared, so the order is A::g, A::f, B::h.
And because the type of b is b, you know what polymorphism and dynamic binding are, and you can understand why the first call is B::g instead of A::g.

In addition, this interview question made a lot of assumptions about the compiler. It is estimated that the question was developed by windows, and I have not seen other platforms. In fact, the results of this question on different compilers are often different. For example, on my 64-bit mac, this code is an execution error, segment fault, because the length of each element of the 64-bit vtbl is 64, which is 2 ints long.

Guess you like

Origin blog.csdn.net/qingzhuyuxian/article/details/108096427