Notes on C++ Object Model Learning 11: Analysis of Virtual Function Table

Knowledge Points:

(1) Only virtual functions can exist in a class. Objects belonging to the same class share virtual function tables, but each has its own vptr (virtual function table pointer), which of course points to the same address (virtual function table header address).

(2) A virtual function in the parent class is equal to a virtual function in the child class.In other words, if there is a virtual function table in the parent class, there must be a virtual function table in the child class.Because you inherit the parent class.
Others think that if the virtual of the parent's virtual functions are removed from the subclasses, are they no longer virtual functions?
As long as it is a virtual function in the parent class, it is still a virtual function in the subclass even if virtual is not written.
But whether it is a parent or a subclass, there will only be one virtual function table. We cannot think that there is one virtual function table in the subclass + there is one virtual function table in the parent class. We can get a conclusion that there are two virtual function tables in the subclass.
Is it possible to have more than one virtual function table in a subclass?We'll explain this later;

(3) If there is no new virtual function in the subclass at all, we can assume that the contents of the virtual function table of the subclass are the same as that of the parent class.
However, just the content is the same, the two virtual function tables are in different places in memory, in other words, they are two tables with the same content.
Each item in the virtual function table holds the first address of a virtual function, but if an item in the virtual function table of the subclass and an item in the virtual function table of the parent class represent the same function (this means that the subclass does not cover the virtual function of the parent class),
The address of the function executed by the table item should be the same.

(4) The contents beyond the virtual function table are unknown;

Summary: Virtual function table follows class, virtual function table pointer follows specific object

The test code is as follows:

// This example demonstrates that objects of a class share a virtual function table. When each object is generated, only a virtual function pointer is added to the object memory, which points to the shared virtual function table, which is in memory

#include <iostream>
using namespace std;

//Parent Class
class Base
{
public:
	virtual void f() { cout << "Base::f()" << endl; }
	virtual void g() { cout << "Base::g()" << endl; }
	virtual void h() { cout << "Base::h()" << endl; }
};
class Derive :public Base
{
	virtual void g() { cout << "Derive::g()" << endl; }
	/* void f() { cout << "Derive::f()" << endl; }
	void g() { cout << "Derive::g()" << endl; }
	void h() { cout << "Derive::h()" << endl; }*/

};

int main()
{
	typedef void(*Func)(void); //Define a function pointer type

	Derive derive;
	long *pvptrderive = (long *)(&derive);
	long *vptrderive = (long *)(*pvptrderive); //0x00b09b6c {project100.exe!void(* Derive::`vftable'[4])()} {11538847}
	Func f1 = (Func)vptrderive[0]; //0x00b0119f {project100.exe!Base::f(void)}
	Func f2 = (Func)vptrderive[1]; //0x00b0150f {project100.exe!Derive::g(void)}
	Func f3 = (Func)vptrderive[2]; //0x00b01325 {project100.exe!Base::h(void)}
	Func f4 = (Func)vptrderive[3]; //0x69726544
	Func f5 = (Func)vptrderive[4]; //0x3a3a6576

	Derive derive2 = derive; //Call copy constructor
	long *pvptrderive2 = (long *)(&derive2);
	long *vptrderive2 = (long *)(*pvptrderive2);

	Base base = derive; //Assigning directly to a parent object with a subclass object allows the compiler to automatically distinguish (cut out) the part of the subclass that belongs to the parent and copy it to the parent object.
						//So Base base = derive; you actually did two things:
						//First thing: Generate a base object
						//Second thing: use derive to initialize the value of the base object.
						//Here the compiler gives us a choice. Obviously when derive initializes the base object,
						//The virtual function table pointer value of derive does not override the virtual function table pointer value of the base object, and the compiler helps us do this.
	long *pvptrbase = (long *)(&base);
	long *vptrbase = (long *)(*pvptrbase); //0x00b09b34 {project100.exe!void(* Base::`vftable'[4])()} {11538847}
	Func fb1 = (Func)vptrbase[0];   //0x00b0119f {project100.exe!Base::f(void)}
	Func fb2 = (Func)vptrbase[1];   //0x00b01177 {project100.exe!Base::g(void)}
	Func fb3 = (Func)vptrbase[2];   //0x00b01325 {project100.exe!Base::h(void)}
	Func fb4 = (Func)vptrbase[3];    //0x00000000
	Func fb5 = (Func)vptrbase[4];    //0x65736142


	//OO (object-oriented) and OB (object-based) concepts:
	//c++ supports polymorphism through pointers and references to classes. This is a programming style, which is what we often call object-oriented.object-oriented model;
	//OB(object-based), also known as the abstract data type model of ADT, does not support polymorphism and performs faster because
	//Because the resolution of function calls does not require runtime decisions (no polymorphism), it is done during compilation and memory space is more compact because there are no concepts such as virtual function pointers and virtual function tables;
	//Base *pbase = new Derive();
	//Base &base2 = derive2;
	//Obviously, OB s are less flexible in design.
	//c++ supports both object-oriented programming (inheritance, polymorphism) (OO) and object-based (OB) programming.

	return 1;
}

Tags: Programming less

Posted on Tue, 09 Jun 2020 21:29:57 -0400 by backslash