C++ compilation and debugging to see the principle of polymorphism

Research on the realization principle of C++ polymorphism

 Polymorphism: The address of the subclass object is assigned to the parent class pointer, and different responses are generated when the same message is received;

//Class A with virtual function
class A
{
	virtual void fun()
	{
	};
};
//Class C with virtual function
class C
{
	virtual void test()
	{
	};
};
//Multiple inheritance of class B that inherits from A and C
class B: public A, public C
{

};
//class D without virtual functions
class D
{
	
};
//There is a function, but not a virtual function
class E
{
	void fun()
	{

	};
};
//Inherit class F with virtual functions
class F: public C
{

};
//G with member variables
class G
{
	int a;
};
int _tmain(int argc, _TCHAR* argv[])
{
	A a;
	B b;
	C c;
	D d;
        F  f;
        cout<<"sizeof(A)"<<sizeof(A)<<endl;//4 If there is a virtual function, a virtual function table will be generated, and a virtual function pointer will occupy 4 bytes in the virtual function table.
	cout<<"sizeof(C)"<<sizeof(C)<<endl;//4 同A
	cout<<"sizeof(B)"<<sizeof(B)<<endl; //8 multiple inheritance will have multiple virtual function tables including A and C virtual function tables totaling 8 bytes
	cout<<"sizeof(D)"<<sizeof(D)<<endl;//1 There is no virtual function, the operating system allocates one byte of memory
	cout<<"sizeof(E)"<<sizeof(E)<<endl;//1 there is a function, the function does not need memory
	cout<<"sizeof(F)"<<sizeof(F)<<endl;//4 Inherit a class C single inheritance has only one virtual function table
	cout<<"sizeof(G)"<<sizeof(G)<<endl;//4 There is an integer member variable that occupies 4 bytes
	system("pause");
	return 0;
}

Output result:

It can be seen from the output results that for ordinary classes, there is no virtual function memory, which is 1. When virtual functions are included, there will be a virtual function table. In the virtual function table, there are virtual function pointers occupying a length of 4 bytes. Single inheritance There is only one virtual function table, and multiple inheritance will have multiple virtual function tables.

Debugging can see the memory structure model:


From the above memory, it can be seen that class D that does not use virtual functions has no virtual function table and virtual function pointer; while F, which inherits class C, has a virtual function pointer, and class B, which inherits both A and C, has both A and C virtual function pointers. Function tables and pointers; what about when the derived class itself has virtual functions?

class H:public A
{
        //Override parent class virtual function
        virtual void fun()
	{
	};
        // own virtual function
	virtual void testfun()
	{

	};
};

Does it mean that virtual functions in derived classes are equivalent to ordinary functions? The virtual function of the non-base class defined in the derived class does not generate a new virtual function table, nor does it exist in the virtual function table of the base class.

class A
{
public:
	virtual void fun()
	{
		printf("%s\n", __FUNCTION__);
	};
	virtual void myfun()
	{
		printf("%s\n", __FUNCTION__);
	};
};

class H :public A
{
public:
	virtual void fun()
	{
		printf("%s\n", __FUNCTION__);
	};
	virtual void testfun()
	{
		printf("%s\n", __FUNCTION__);
	};

	void testfun1()
	{
		printf("%s\n", __FUNCTION__);
	};
};

int _tmain(int argc, char* argv[])
{
	H h;

	// I compiled it for x32, if it is an x64 program, replace unsigned int with unsigned long long
     unsigned int vptr = *((unsigned int *)(&h));
     printf("%p\n", vptr);
     unsigned int vfun1 = *((unsigned int *)(vptr));
     printf("%p\n", vfun1);
     unsigned int vfun2 = *((unsigned int *)(vptr) + 1);
     printf("%p\n", vfun2);
     unsigned int vfun3 = *((unsigned int *)(vptr) + 2);
     printf("%p\n", vfun3);
     unsigned int vfun4 = *((unsigned int *)(vptr) + 3);
     printf("%p\n", vfun4);
typedef void(*Fun)(void);Fun pfun = (Fun)vfun1; //输出 H::fun(); pfun();pfun = (Fun)vfun2; //输出 A::myfun(); pfun();pfun = (Fun)vfun3; //输出 H::testfun(); pfun();system("pause");return 0;}

003D7B00 belongs to the starting address of the virtual function pointer

003D12B7 H::fun address

003D12C6 A::fun address

003D12B2 H::testfun address indicates that the virtual function of the derived class is also stored in the virtual function table, but it is not displayed on the compiler (personal opinion, please correct me if it is wrong)

00000000 NULL I thought this location was the address of an ordinary function, but ordinary functions will not be stored in the virtual function table

There is a difference between virtual functions and ordinary functions of derived classes. Compilers don't handle it the same way.

Debug to see polymorphism:

class Base
{
public:
	virtual void Name()
	{
		cout<<"Base:: Name()"<<endl;
	};

	virtual void Age()
	{
		cout<<"Base :: Age()"<<endl;
	};

	virtual void Sex()
	{
		cout<<"Base :: Sex()"<<endl;
	};
};


class Derived1 : public Base
{
	virtual void Name()
	{
		cout<<"Derived1:: Name()"<<endl;
	};

	virtual void Age()
	{
		cout<<"Derived1 :: Age()"<<endl;
	};

	virtual void Sex()
	{
		cout<<"Derived1 :: Sex()"<<endl;
	};
};

class Derived2 : public Base
{
	virtual void Name()
	{
		cout<<"Derived2:: Name()"<<endl;
	};

	virtual void Age()
	{
		cout<<"Derived2 :: Age()"<<endl;
	};

	virtual void Sex()
	{
		cout<<"Derived2 :: Sex()"<<endl;
	};
};

class Derived3 : public Base
{
	
};

int _tmain(int argc, _TCHAR* argv[])
{
    Derived1 d1;
	Derived2 d2;
	Derived3 d3;
	basis * basis;
	Base    base1;
	base = &d1;
	base->Name();

	base = &d2;
	base->Name();

 	system("pause");
	return 0;
}

As can be seen from the above, the base class vfptr pointer address 00f07958 derived class d1: vfptr pointer 00f078b8; d2: vfptr pointer 00f0785c;



From the memory point of view, if it is a pure base class, the address in the virtual function table is the address of the base class function; 00f07958 vfptr pointer points to the address of the base1 base class

However, when the base class pointer is assigned the address of the object such as the address 00f00785c vfptr points to the vfptr pointer of the derived class Derived1, the virtual function table is replaced by the virtual function table of Derived1. The address is indeterminate at compile time. Only at runtime, after assigning a value to the parent class pointer, the pointer will change, and then we know which function to call at runtime;

When you assign it to another subclass object, the corresponding address will also change. You can see that after the assignment is changed, vfptr changes to 00f078b8, which is the virtual function pointer address of the second derived class;

Output result:


       I think the principle of polymorphism is that if a class contains a virtual function, then the class will generate a virtual function table vftable when it is instantiated. There is a virtual function pointer vfptr in the virtual function table, and the virtual function is in the virtual function table. The position in is determined according to the order of declaration; when creating a pointer to the base class object, this pointer is nothing at this time, pointing to NULL, when you assign a subclass object to it, the base class The vftable of the pointer will be replaced with the vftable virtual function table of the subclass after the assignment. At this time, the vfptr pointer also points to the virtual function address of the subclass (I think this process is called dynamic binding); only when the base class is passed The pointer can find the address of the derived class function, and the function of the base class will not be called when running, because the virtual function table has been replaced, and only the function address of the derived class can be found through the vfptr pointer.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325772848&siteId=291194637