Visual Studio查看虚函数表&C++内存模型

Visual Studio查看虚函数表&C++内存模型_第1张图片
Visual Studio查看虚函数表&C++内存模型_第2张图片
在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存布局,如果写上/d1 reportSingleClassLayoutXXX(XXX为类名),则只会打出指定类XXX的内存布局。近期的VS版本都支持这样配置。

运行程序的话就会自动生成一张虚函数表了:

#include 
using namespace std;

class Base {
public:
	int a = 0;
	int b = 0;
	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 {
	void g() { cout << "Derive::g" << endl; }
	virtual void g1() { cout << "Derive::g" << endl; }
};

int main()
{
	
	system("pause");
	return 0;
}

Visual Studio查看虚函数表&C++内存模型_第3张图片

这个内存结构图分成了两个部分,上面是内存分布,下面是虚表。

单一继承(含成员变量+虚函数+虚函数覆盖)

Visual Studio查看虚函数表&C++内存模型_第4张图片
通过代码查看的虚函数表是这样的:
Visual Studio查看虚函数表&C++内存模型_第5张图片

多继承(含成员函数+虚函数+虚函数覆盖)

Visual Studio查看虚函数表&C++内存模型_第6张图片
2个int型,一个short型(2字节padding后占4个字节),2个虚函数表,所以长度为5*4 = 20;虚函数表是这样的:
Visual Studio查看虚函数表&C++内存模型_第7张图片
内存布局是这样:
Visual Studio查看虚函数表&C++内存模型_第8张图片

深度为2的继承(成员变量+虚函数+虚函数覆盖)

Visual Studio查看虚函数表&C++内存模型_第9张图片
3个int型,1个short型(2字节padding后占4个字节),2个虚函数表;代码显示的类的布局是这样:
Visual Studio查看虚函数表&C++内存模型_第10张图片
内存布局:
Visual Studio查看虚函数表&C++内存模型_第11张图片

class A {
public:
	virtual void f1() { cout << "A:f1" << endl; };
	virtual void f2() { cout << "A:f2" << endl; };
	virtual void f3() { cout << "A:f3" << endl; };
};

class B {
public:
	virtual void g1() { cout << "B:g1" << endl; };
	virtual void g2() { cout << "B:g2" << endl; };
	virtual void f2() { cout << "B:f2" << endl; };
};

class C :public A, public B {
	virtual void f1() { cout << "C:f1" << endl; };
	virtual void g1() { cout << "C:g1" << endl; };
};

class D :public C {
	virtual void f1() { cout << "D:f1" << endl; };
	virtual void g2() { cout << "D:g2" << endl; };
};

显示的内存分布是这样的:
Visual Studio查看虚函数表&C++内存模型_第12张图片

重复继承(含成员变量+虚函数+虚函数覆盖)

Visual Studio查看虚函数表&C++内存模型_第13张图片
Visual Studio查看虚函数表&C++内存模型_第14张图片
由于基类中的m_nAge在内存分布中出现了两次,所以最后的结果是5个int类型和2个虚函数表,共计28字节。
Visual Studio查看虚函数表&C++内存模型_第15张图片

单一虚继承(含成员变量+虚函数+虚函数覆盖)

Visual Studio查看虚函数表&C++内存模型_第16张图片
所谓的虚继承就是把继承语法前加上virtual关键字,例如class B:virtual public A{…};
虚拟继承的出现就是为了解决重复继承中多个间接父类(可以解决菱形问题)的问题的 。内存分布是这样的:
Visual Studio查看虚函数表&C++内存模型_第17张图片
这里需要解释下,因为出现了vfptr与vbptr,vfptr常见,但是vbptr却是第一次见,它指向CChildren的vbtable,另一个CChildren的vfptr位于0地址偏移处,它指向CChildren的vftable。从截图中也可以看出有2个vftable与1个vbtable(一共3个表)。vbtable中的8表示vbptr与基类的vfptr(这里即_vfptr::CParent)之间的偏移量(记录了基类vfptr的地址,即二重指针)。
Visual Studio查看虚函数表&C++内存模型_第18张图片
另外提及一下,如果CChildren里全部是重载基类中的虚函数的话,或者说没有新的虚函数的话,_vfptr::CChildren指向的虚函数表就是空的,所以计算大小的时候可以不用算进去,因为实际上并没有创建相应的表格。
举个例子:

class A {
public:
	virtual void f1() { cout << "A:f1" << endl; };
	virtual void f2() { cout << "A:f2" << endl; };
	virtual void f3() { cout << "A:f3" << endl; };
};

class B:virtual A {
public:
	//virtual void g1() { cout << "B:g1" << endl; }; //如果打开注释,那么B就会有自己的vfptr
	void f2() { cout << "B:f2" << endl; };
	void f3() { cout << "B:f3" << endl; };
};

内存分布为:
Visual Studio查看虚函数表&C++内存模型_第19张图片
即此时B类没有自己的vfptr。

多虚继承(含成员变量+虚函数+虚函数覆盖)

(1)CParent2是虚继承,CParent1是一般继承

Visual Studio查看虚函数表&C++内存模型_第20张图片
Visual Studio查看虚函数表&C++内存模型_第21张图片
Visual Studio查看虚函数表&C++内存模型_第22张图片

(2)CParent1是虚继承,CParent2是一般继承

Visual Studio查看虚函数表&C++内存模型_第23张图片
Visual Studio查看虚函数表&C++内存模型_第24张图片

(3)CParent1和CParent2都是虚继承

Visual Studio查看虚函数表&C++内存模型_第25张图片
Visual Studio查看虚函数表&C++内存模型_第26张图片
从这里可以看出vbtable确实是存储了指向相应的基类的vfptr的地址(二重指针)。

菱形的虚拟多重继承(含成员变量+虚函数+虚函数覆盖)

Visual Studio查看虚函数表&C++内存模型_第27张图片
Visual Studio查看虚函数表&C++内存模型_第28张图片
Visual Studio查看虚函数表&C++内存模型_第29张图片

你可能感兴趣的:(工作,c++,visual,studio)