Try to understand virtual functions thoroughly! (test platform: vs2018+win10)

First, link to several blog addresses: Analysis of C + + virtual function table

 cout << "Virtual function table address:" << (int*)(&b) << endl;

        cout << "Virtual function table - first function address:" << (int*)*(int*)(&b) << endl;

In this blog, cout < < virtual function table address: "< (int *) (& b) < < endl; This statement is wrong. The address obtained by this method is not the address of the virtual function table, but the first address of object b, that is, the address where the pointer of the virtual function table is stored.
Learning experience of C + + virtual function table from class instance address to virtual function table and then to virtual function address
This explanation is more detailed.

When it comes to virtual functions, the concept is very simple, that is, the address of virtual functions is stored in the virtual function table. Runtime polymorphism is realized by virtual function and virtual function table. There will be a pointer to the virtual table address inside the class. The virtual function is called through this pointer. The following is an advanced version of the understanding of the following concepts: how to further understand virtual functions from memory addresses.

First, several problems are explained: function pointer definition: typedef void (* fun) (void)// Right? Fun is defined as a function pointer that returns void type without parameters (pay attention to the difference between pointer functions)
Virtual function table, virtual table pointer;

This is the diagram of virtual function memory allocation in the second blog. First, define the related virtual functions:

class Base{
public:
	virtual void f(){
		cout<<"base f()"<<endl;
	}
	virtual void g(){
		cout<<"base g()"<<endl;
	}
};
class Derived:public Base{
public:
	void f(){
		cout<<"derived f()"<<endl;
	}
	void g(){
		cout<<"derived g()"<<endl;
	}
};

typedef void (*pFun)(void);
int _tmain(int argc, _TCHAR* argv[])
{
		Derived d;
	cout << "d Value of the first address of:" << &d << endl;
	cout << "d First address content:" << *(int*)&d << endl;
	cout << "The value of the first address of the virtual function table and the value of the memory address where the first entry of the virtual function table is located:" << (int*)*(int*)&d << endl;
	cout << "Contents of the first item of the virtual function table Derived::f()Value of function first address:" << *(int*)*(int*)&d << endl;
	cout << "Value of the second entry address of the virtual function table:" << (int*)*(int*)&d + 1 << endl;
	cout << "Contents of the second item of the virtual function table Derived::g()Value of function first address:" << *((int*)*(int*)&d + 1) << endl;
	pFun p = (pFun)(*(int*)*(int*)&d);
	p();
	cout << "The first address the function pointer points to p():" << p << endl;
	p = (pFun)(*((int*)*(int*)&d + 1));
	p();
	cout << "The second address the function pointer points to p():" << p << endl;
	int i;
	cin >> i;
	return 0;
}

result
First address value of d: 0118F808
d first address content: 5872472
The value of the first address of the virtual function table and the memory address of the first entry of the virtual function table: 00599B58
Value of the first entry content of virtual function table and the first address of Derived::f() function: 5837940
Value of the address of the second entry in the virtual function table: 00599B5C
The content of the second entry of the virtual function table and the value of the first address of the Derived::g() function: 5837975
derived f()
The first address pointed to by the function pointer (P): 00591474
derived g()
The second address pointed to by the function pointer (P): 00591497

First define the object and get the first address of the object, that is & b. then, because there is a virtual function in the object b, considering that the virtual function pointer is generally of type int, Take the first four bytes (different platforms) as (int) & b (the printed address is the same as & b, which is the first address. By the way, understand the meaning of the pointer). The stored content is the address of the virtual function, which needs to dereference the pointer, that is * (int *) & b, (why not use & (int *) & b?, If you try, you will report an error, which involves the problem of left and right values, & it can only be used if it is an lvalue (with an address);
Be sure to note that * * (int *) & D and (int *) (int) & D * actually print the same value, except that the former is represented by hexadecimal and the latter is represented by hexadecimal. The second and third addresses here are actually the same, but they are different in hexadecimal, so they look different. They are actually an address.
The address obtained by function pointer is indeed the same as the address obtained by taking address, but one is hexadecimal (pointer) and the other is decimal (taking address);
In addition, how to execute programs from absolute addresses? Link: Execute program from absolute address

Keywords: C C++ pointer Polymorphism

Added by ac1982 on Sat, 25 Dec 2021 19:35:10 +0200