欢迎来到Introzo百科
Introzo百科
当前位置:网站首页 > 技术 > vs2010查看函数列表_具有虚函数的类的大小 & VS2010命令行查看虚函数表和类内存布局

vs2010查看函数列表_具有虚函数的类的大小 & VS2010命令行查看虚函数表和类内存布局

日期:2023-09-15 22:25

查看目录在这

但是你直接选取下拉,是没有显示的如下

这是因为你需要指定函数开头

比如说

此时再去下拉

嘿嘿嘿? 这是不是你想要的效果

?

虚函数的原理可查看

http://www.introzo.com/malecrab/p/5572730.html

http://www.introzo.com/malecrab/p/5573368.html

一 VS2010命令行查看虚函数表和类内存布局

以下内容引自

VS2010命令行下查看虚函数表和类内存布局

——《深度探索C++对象模型》读书札记系列

?

在学习多重继承下的Virtual functions时,需要分析派生类的虚函数表(vtable),但是在网上找了好几种Hack vtable方法,结果都不尽如人意。没想到MS Compiler(以VS2010为例)有打印vtable的编译选项,真是太好了!

1. 打开“Visual Studio Command Prompt (2010)”,如下

该CMD下具有VS2010命令行下的一些编译、链接等工具,例如cl.exe。

?

2. 编写一个cpp文件

以《深度探索C++对象模型》的160页的代码(160.cpp)为例,如下

[cpp]

view plain

copy

class?Base1?{??public:??????Base1();??????virtual?~Base1();??????virtual?void?speackClearly();??????virtual?Base1*?clone()?const;??protected:??????float?data_Base1;??};????class?Base2?{??public:??????Base2();??????virtual?~Base2();??????virtual?void?mumble();??????virtual?Base2*?clone()?const;??protected:??????float?data_Base2;??};????class?Derived?:?public?Base1,?public?Base2?{??public:??????Derived();??????virtual?~Derived();??????virtual?Derived*?clone()?const;??protected:??????float?data_Derived;??};????int?main(void)??{??????return?0;??}??

3、使用cl命令的/d1 reportAllClassLayout或reportSingleClassLayoutXXX选项。这里的reportAllClassLayout选项会打印大量相关类的信息,一般用处不大。而reportSingleClassLayoutXXX选项的XXX代表要编译的代码中类的名字(这里XXX类),打印XXX类的内存布局和虚函数表(如果代码中没有对应的类,则选项无效)。

举例如下

[cpp]

view plain

copy

cl?/d1?reportSingleClassLayoutBase1?160.cpp??

运行结果下

可以看出Base1的大小为8个字节,共有3个虚函数,分别是~Base1、speackClearly和clone,对于学习上述的示例代码绰绰有余咯~~

二 具有虚函数的类的大小

以下内容引自

一般的书上都说,虚函数是在运行时根据对象的实际类型“动态决定”函数入口。但什么是“动态决定”呢?实际上C++编译器在实现这个功能的时候,并非真的 等到虚函数被调用时才去判断这个对象是什么类型的。下面我用一个简单的图表来说明C++编译器到底干了些什么。假设有两个类

[cpp]

view plain

copy

struct?Base?{????virtual?void?f();????virtual?void?g();??};??struct?Derived?:?public?Base?{????virtual?void?f();????virtual?void?g();??};??

Base 和 Derived 各有一个虚表,分别是 VTable_B 和 VTable_D ,那么编译器是怎么通过只用一个虚表指针来实现下面的“动态”调用呢?

[cpp]

view plain

copy

Base?*pB?=?new?Derived();??pB->f();??

先让我们看Base和Derived对象是怎么存储的,以及两个类的虚表结构

Base:? ?? ?? ?? ?? ?? ???VTable_B:

------------? ?? ?? ?-------------

|??vptr? ?? ? |? ?? ???|??f() 入口? ? |

+---------+? ?? ???+----------+

|??Base的? ?|? ?? ???|??g() 入口? ?|?

|? ? 数据? ???|? ?? ???-------------

------------

Derived:? ?? ?? ?? ?? ? VTable_D:

------------? ?? ???--------------

|??vptr? ?? ? |? ?? ???| f() 入口? ???|

+---------+? ?? ???+----------+

|??Base的? ?|? ?? ???| g() 入口? ? |

|? ? 数据? ???|? ?? ???-------------

+---------+

| Derived的|

|? ? 数据? ???|

------------

pB 指针既可以指向 Base 对象,也可以指向 Derived 对象,所以 pB 本身是不确定的。但是,任何对象本身却从被 new 出来开始就是确定的,所以 Base 对象在构造时,编译器会往 vptr 中填上 VTable_B 的地址,而 Derived 对象在构造时,编译器会往 vptr 中填上 VTable_D 的地址。 等到虚函数被调用的时候,也就是 pB->f() 这行语句被执行的时候,编译器并不需要知道 pB 到底是指向 Base 还是 Derived ,它只要直接用 vptr 就能找到正确的虚表和虚函数入口了,父类和子类的虚表结构是相似的,同一个虚函数入口在父表和子表的偏移量都是一样的。 通过上面这些介绍,我想你应该能理解,为什么在单一继承的条件下,不管有多少层继承,每个对象只需一个 vptr 就行了。 多重继承的条件下,一个 vptr 行不行呢? 不行。多重继承的时候,虚函数既有来自父类1的,也有来自父类2的,所以这些虚函数入口是不能放在同一个虚表当中的。假设 Derived 除了 Base外,还继承 Base2,并且 Base2 中有两个虚函数 x() 和 y (),那么 Derived 对象的存储结构也许是这样的(只是大概,和具体编译器相关)。 Derived:? ?? ?? ?? ?? ? VTable_D: ------------? ?? ???-------------- |??vptr? ?? ? |? ?? ???| f() 入口? ???| +---------+? ?? ???+----------+ |??Base的? ?|? ?? ???| g() 入口? ? | |? ? 数据? ???|? ?? ???------------- +---------+ | vptr2? ?? ?|? ?? ?? ? VTable_D2: +---------+? ?? ???------------- | Base2的??|? ?? ???|??x() 入口? ? |? |? ? 数据? ???|? ?? ???+-----------+ +---------+? ?? ???| y() 入口? ???| | Derived的|? ?? ???------------- |? ? 数据? ???|

以下内容引自

本文版权归作者 kanego 和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

三 案例分析1:

如下程序:

[cpp]

view plain

copy

#include???using?namespace?std;????????class?A??{??????int?a;??public:??????virtual?void?af(){}??????virtual?~A(){}//如果注释,那么class?D的大小变为12,这点想不通??};????class?B?:?public?A??{??????int?b;??public:??????virtual?void?bf(){}??????virtual?~B(){?/*cout?<

输出结果:

[plain]

view plain

copy

A=8??B=12??C=12??D=28??请按任意键继续.?.?.??

案例分析:

类A有一个虚函数表占4个字节,有自己int类型占4个字节,所以sizeof(A) = 8;

类B继承类A,属于单继承,所以类B只有一个虚函数表指针,占4个字节,继承自A的int变量,还有自身的int变量,所以sizeof(B) = 12;

类C与类B相似;

类D继承自B和C,有两个虚函数表指针,占据8个字节,继承自B的成员变量占8个字节,继承自C的成员变量占8个字节,自身有一个int变量占4字节,所以sizeof(D) = 28。

四 案例分析二:

空类所占内存大小:

class CBase? {? };? sizeof(CBase)=1;

为什么空的什么都没有是1呢? c++要求每个实例在内存中都有独一无二的地址。//注意这句话!!!!!!!!!! 空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。

程序:

[cpp]

view plain

copy

class?A??{??};??class?A2??{??};????class?B?:public?A??{??};????class?D?:public?A,?public?A2??{??};????class?C?:public?virtual?B??{??};????int?main()??{??????cout?<

运行结果:

[cpp]

view plain

copy

1??1??4??1??请按任意键继续.?.?.??

注:B继承A存在空白基类优化现象,在空基类被继承后(单继承),由于空基类没有任何数据成员,所以让其在子类的对象布局中优化掉空基类所占用的一个字节。

说明:空类、单一继承的空类、多重继承的空类空间为1,

但是虚继承涉及到虚表(虚指针),所以sizeof(C)的大小为4

五 案例分析三:

[cpp]

view plain

copy

class?A??{??};????class?B?:public?A??{??public:??????virtual?void?f1(){}??};????class?C?:public?A??{??public:??????virtual?void?f1(){}??};????class?D?:public?virtual?B,C??{??};????int?main()??{??????cout?<

为什么sizeof(D) =12呢?

六 案例分析四:

[cpp]

view plain

copy

class?A??{??};??class?B??{??};??class?D??{??};??class?E??{??};??class?F??{??};????class?C:public?A,public?B,public?D,public?E,public?F??{??};????class?M?:public?A,?public?B??{??????//大小1??};????int?main()??{????????cout?<

输出结果4,1为什么呢?

多继承的情况下,为了区分各个不同的基类子对象,这些基类子对象必须具有不同的地址,所以这时候不能使用空基类优化,但单继承就可以,因为对于单继承,基类子对象与最终派生类对象地址相同的情形是允许的。

同时要注意,空基类优化只能存在于基类子对象,当空类对象作为完整对象时,是不能优化的,因为C++规定,每个完整对象都必须具有唯一的地址。空类完整对象的大小并不是只能为1,而是至少为1,有些编译器会加入内存对齐的因素,所以有些编译器的空类完整对象的大小会是4或者8等等。

注:若A含有静态数据成员,但是在c++里,静态成员被单独存储在全局区(静态区),所以它同样不影响A的大小。

总结:

[cpp]

view plain

copy

class?A//sizeof(A)=1??{};????class?S:public?A//单继承,空基类优化,sizeof(S)=4??{??????int?a;??};????class?B//B是空类??{??????//没有任何数据成员的类成为空类,这里的数据成员不仅仅包括类的成员变量??????//同时还包括编译器为了某种目的引入的数据成员??????//比如:为了支持多态而引入的虚指针vptr,为了支持虚继承而引入的必要的虚基类指针,而且还包括从??????//基类直接或间接继承而来的上述的数据成员。??????void?fun(){}??};????class?C??{??};????class?D:public?A,?B//双继承,空基类优化,但是只能优化一个,sizeof(D)=8??{??????int?a;??};????class?E:public?A,?B,?C//三重继承,空基类优化一个,sizeof(E)=2??{??};????class?F:public?E//单继承且E为空,空基类优化,?sizeof(F)=1;??{??????void?fun(){}??};????class?G:public?F//单继承,空基类优化,sizeof(G)=1??{??};????class?M{?int?a;?};??class?N?:public?M{};??class?O?:public?N{};??class?P?:public?N,?A{};??class?Q?:public?N,?A,?B{};????int?main()??{????????cout?<

运行结果:

[plain]

view plain

copy

A1??S4??B1??C1??D8??E2??F1??M4??N4??O4??P4??Q8??请按任意键继续.?.?.?

转载自:http://www.introzo.com/qianqin_2014/article/details/51464007

step 1:将***.dll文件拷贝至如图中所示的路径下。

step 2:打开windons命令处理程序(win+R,input “cmd ”?),进入到vs2010的安装目录“Microsoft Visual Studio 10.0\VC”中,输入“dumpbin -exports ***.dll”即可获取函数列表,如下图:

关灯