c++类中常有这样的函数ClassA() = 0excel 等于函数0起什么作用?谢谢

c++类中:的作用是什么_百度知道
c++类中:的作用是什么
初始化列表,后面的表达式用于初始化它的成员变量,或者基类的成员变量 class A{public: A():i(123)/////相当于给i赋值 {
} A(int a) {
i = }private: };class B:public A{public: B():A(1), b(456)////相当于调用A的有参构造函数,b相当于赋值为456 { }private: };
其他类似问题
为您推荐:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁C++程序问题: 这个shape类为啥没有构造函数? virtual void draw()const=0;起什么作用,谢谢!_百度知道
C++程序问题: 这个shape类为啥没有构造函数? virtual void draw()const=0;起什么作用,谢谢!
&math: public Shape {
delete pt2.h&gt, 0); &&
s-&)'&;Distance = &
s = pt2, 4);
Point* pt2 = new Point(0;& &using namespace std,y_:draw() const{
cout &class Shape {
s-&gt.y_)*(y_ -&
delete pt1;&
Shape* s = pt1;
double distance(const Point &pt ) const
return sqrt((x_ - endl.x_) + (y_ -&
x_&lt, y_(y)
virtual void draw() const:
&#47.y_)) ;/ ' &#39,'&lt::
double x_;**********found**********
virtual void draw()const=0;distance(*pt2) &'& pt1-& &draw();void Pclass P
virtual ~Shape() { }}:
Point(double x源程序如下:(用于求两点间的距离)#include &lt, double y) ;};draw();y_
&&#include &}int main(){
Point* pt1 = new Point(3.x_)*(x_ - &lt:
x_(x);('}iostream&
提问者采纳
baidu.baidu://e.baidu,抽象类不能实体化.hiphotos://c://f.hiphotos.jpg" /><img class="ikqb_img" src="http.baidu.hiphotos.jpg" esrc="http原因是这个shape类是一个抽象类。<a href="http,这是固定的写法.com/zhidao/wh%3D450%2C600/sign=e05877adf11f3a295a9dddcaacfd9f9d72abba94
这是一道程序填空题,found后面是一个空,我以为要填构造函数,结果答案是这个,感觉有些蹊跷。
按照你的意思,那么析构函数也删除了是可以的吧?......,还有,draw怎么来的?
答案肯定不是构造函数,析构不能删除,draw是shape这个抽象类声明的纯虚函数,需要派生类来实现真正的功能。
析构函数删了没事
感觉上没事,但实际上是不行的,析构函数不可以删的。
提问者评价
谢谢,虽然还有疑问,不过这道题会做了
其他类似问题
为您推荐:
其他1条回答
没有写构造函数系统会自动的隐式添加一个默认的构造函数那个函数的格式是纯虚函数的声明,这样方便在以后的继承类里进行函数的重载
构造函数的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁C++类虚函数逆向学习总结
标 题:C++类虚函数逆向学习总结
作 者:dragonyjd
时 间:<font color="#08-03-02 18:27 链 接:
[摘要]受menting影响,也对C++也逆向了一把.由于刚刚接触逆向,都是自己学习总结的,又是第一次发贴,因此不免有误解之处,还请各位多多指教,谢谢.
[正文]先来看一下C++类的虚函数的实例:
class&clsC
&&int&m_c;
&&clsC(){m_c=0;}
&&~clsC(){};
&&void&show(){cout&&&I'm&in&BaseC&Class.&;};
&&void&show2(){cout&&&I'm&in&BaseC&Class2.&;}
class&clsB:public&clsC
&&int&m_b;
&&clsB(){m_b=0;}
&&~clsB(){};
&&virtual&void&show(){cout&&&I'm&in&BaseB&Class.&;}
&&virtual&void&show2(){cout&&&I'm&in&BaseB&Class2.&;}
class&clsA:public&clsB
&&int&m_a;
&&int&m_b;
&&int&m_c;
&&~clsA(){};
&&virtual&void&show(){cout&&&I'm&in&sub&Class.&;}
clsA::clsA():m_b(1),m_c(2),m_a(0)
void&main()
&&clsA&a;&&&&&&&//局部实例类,main函数反汇编代码如下:
&&clsB&*pb&=&&a;
&&clsC&*pc&=&&a;
&&pb-&show2();
&&pc-&show();
sub&esp,24&在堆栈中为局部变量a和指针pb、pc、临时指针分配36字节.其中clsA类大小为24字节(clsA有3*4=12字节成员变量,&clsB有4字节成员变量,&clsC有4字节成员变量,虚函数有个指向vtable的虚函数表指针,占4字节.因此一共12+4+4+4=24)
构造函数反汇编如下:
派生类的构造函数首先调用基类的构造函数,基类clsB的构造函数如下:
类clsB的构造函数又调用基类clsC的构造函数:
由于顶层基类clsC无虚函数,因此可见,clsB类的虚函数表vtable指针也占用类的第1个DWORD空间.故类的派生结构体系中,如果存在虚函数,则虚函数表vtable指针一定占用类的第1个DWORD位置.基类clsB的构造函数将基类的所有虚函数的地址存放到虚函数地址表vtable中:
&&&&下面看一下这两个地址所指向的汇编代码:
可见基类clsB的虚函数表指向基类clsB的虚函数地址show()和show2()
但基类构造完后,派生类的构造函数改写了这个虚函数表vtable指针.下面看下派生类的虚函数表vtable指针:
&&&&下面看一下这两个地址所指向的汇编代码:
由于派生类无show2()函数,因此可见派生类的虚函数表指向派生类的虚函数地址show()和基类的虚函数show2().
因此,整个构造函数中,派生类的虚函数表vtable指针会改写基类的虚函数表vtable指针来实现虚函数的特性.以后调用虚函数时直接从虚函数表vtable中获取函数的地址来调用.
如果派生类中没有重写基类的某虚函数,则将在派生类的虚函数表vtable中使用基类的某虚函数地址.
这里pc-&show();的调用由于为非虚函数,因此不再使用虚函数特性.反汇编代码显示在编译时使用了clsC::&show()函数地址的硬编码的调用方式.
最后整个clsA类在栈的分配结构图如下:
标 题:虚基类
作 者:dragonyjd
时 间:<font color="#08-03-02 18:42
下面继续分析一下虚基类:
&&int&m_w1;
&&int&m_w2;
&&w(){m_w1=m_w2=0;}
class&clsB:virtual&public&w
&&int&m_b;
&&clsB(){m_b=0;}
&&~clsB(){};
class&clsC:virtual&public&w
&&int&m_c;
&&clsC(){m_c=0;}
&&~clsC(){};
class&clsA:public&clsB,public&clsC
&&int&m_a;
&&int&m_b;
&&int&m_c;
&&~clsA(){};
clsA::clsA():m_b(1),m_c(2),m_a(0)
void&main()
clsA&a;&&&&&&&//局部实例类,main函数反汇编代码如下:
sub&esp,24&在堆栈中为局部变量a分配clsA类大小字节(clsA有3*4=12字节成员变量,&clsB有4字节成员变量+指向虚基类的指针4字节,&clsC有4字节成员变量+指向虚基类的指针4字节,&w有2*4=8字节成员变量.因此一共12+8+8+8=0x24)空间.
构造函数反汇编如下:
虚基类w的构造函数:
基类clsB的构造函数:
基类clsC的构造函数:
在堆栈中为变量a分配起始地址为:&0012FF5C,下图展示clsA类在栈的分配图:
可见前2个DWORD字节为基类clsB所占空间,&clsB的第一个DWORD存放指向基类W的描述指针,看下指针指向数据结构:&
&&&&该结构包含2个DWORD大小,第一个DWORD为0,第2个DWORD表示基类clsB的地址至虚基类w地址的偏移长度(C=0012FF78)
同理,&在上图的第3,4个DWORD位置为基类clsC所占空间,&clsC的第一个DWORD存放指向基类W的描述指针,看下指针指向数据结构:&
&&&&该结构包含2个DWORD大小,第一个DWORD为0,第2个DWORD表示基类clsC的地址至虚基类w地址的偏移长度(=0012FF78)
因此,整个clsA类在栈的分配结构图如下:
标 题:虚基类中包含虚函数
作 者:dragonyjd
时 间:<font color="#08-03-02 19:02
受linxer的提醒,对虚拟继承中有虚函数的情况进行了分析,果然与前两个实例结果太不一样。同时也发现了一个自己不太清楚的问题,希望能得到各位高手解答。
感谢combojiang的小提示,使我有了初步的认识。
感谢看雪论坛提供了这个平台。把我自己的学习总结拿出来与大家分享,最终发现自己认识的不足,学到了新的知识点。
#include&&iostream&
using&namespace&
&&&&int&m_w1;
&&&&int&m_w2;
&&&&w(){m_w1=m_w2=0;}
&&&&~w(){};
&&&&virtual&void&show(){cout&&&I'm&in&W&Class.&;}
&&&&virtual&void&show2(){cout&&&I'm&in&W&Class2.&;}
class&clsC:virtual&public&w
&&&&int&m_c;
&&&&clsC(){m_c=0;}
&&&&~clsC(){};
&&&&void&show(){cout&&&I'm&in&clsC&Class.&;};
&&&&void&show2(){cout&&&I'm&in&clsC&Class2.&;}
class&clsB:virtual&public&w
&&&&int&m_b;
&&&&clsB(){m_b=0;}
&&&&~clsB(){};
&&&&virtual&void&show(){cout&&&I'm&in&clsB&Class.&;}
&&&&virtual&void&show2(){cout&&&I'm&in&clsB&Class2.&;}
class&clsA:public&clsB,public&clsC
&&&&int&m_a;
&&&&int&m_b;
&&&&int&m_c;
&&&&clsA();
&&&&~clsA(){};
&&&&virtual&void&show(){cout&&&I'm&in&clsA&Class.&;}
&&&&virtual&void&show2(){cout&&&I'm&in&clsA&Class2.&;}
clsA::clsA():m_b(1),m_c(2),m_a(0)
void&main()
&&&&clsA&a;
&&&&clsB&*pb&=&&a;
&&&&clsC&*pc&=&&a;
&&&&pb-&show();
&&&&pc-&clsC::show2();
先来看一下类的继续关系结构图:
main函数反汇编代码如下:
004010DB&&/$&&55&&&&&&&&&&&&push&&&&ebp
004010DC&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
004010DE&&|.&&6A&FF&&&&&&&&&push&&&&-1
&&|.&&68&169E4000&&&push&&&&00409E16&&&&&&&&&&&&&&&&&&&&&&&&&;&&SE&处理程序安装
&&|.&&64:A1&0000000&mov&&&&&eax,&dword&ptr&fs:[0]
004010EB&&|.&&50&&&&&&&&&&&&push&&&&eax
004010EC&&|.&&64:&mov&&&&&dword&ptr&fs:[0],&esp
&&|.&&83EC&38&&&&&&&sub&&&&&esp,&38
&&|.&&6A&01&&&&&&&&&push&&&&1&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&/Arg1&=&
&&|.&&8D4D&C8&&&&&&&lea&&&&&ecx,&dword&ptr&[ebp-38]&&&&&&&&&&;&|利用ecx传递变量a的this指针
004010FB&&|.&&E8&00FFFFFF&&&call&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&\变量a的构造函数
&&|.&&C745&FC&00000&mov&&&&&dword&ptr&[ebp-4],&0
&&|.&&8D45&C8&&&&&&&lea&&&&&eax,&dword&ptr&[ebp-38]&&&&&&&&&&;&&指向变量a的clsB基类
0040110A&&|.&&8945&C4&&&&&&&mov&&&&&dword&ptr&[ebp-3C],&eax&&&&&&&&&&;&&clsB&*pb&=&&a;
0040110D&&|.&&8D4D&C8&&&&&&&lea&&&&&ecx,&dword&ptr&[ebp-38]
&&|.&&85C9&&&&&&&&&&test&&&&ecx,&ecx
&&|.&&74&08&&&&&&&&&je&&&&&&short&0040111C
&&|.&&8D55&D0&&&&&&&lea&&&&&edx,&dword&ptr&[ebp-30]&&&&&&&&&&;&&指向变量a的clsC基类
&&|.&&8955&BC&&&&&&&mov&&&&&dword&ptr&[ebp-44],&edx&&&&&&&&&&;&&将指向变量a的clsC基类指针保存到临时变量中
0040111A&&|.&&EB&07&&&&&&&&&jmp&&&&&short&
0040111C&&|&&&C745&BC&00000&mov&&&&&dword&ptr&[ebp-44],&0
&&|&&&8B45&BC&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-44]&&&&&&&&&&;&&指向变量a的clsC基类的临时变量
&&|.&&8945&C0&&&&&&&mov&&&&&dword&ptr&[ebp-40],&eax&&&&&&&&&&;&&clsC&*pc&=&&a;
&&|.&&8B4D&C4&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-3C]&&&&&&&&&&;&&clsB在在变量a的地址
0040112C&&|.&&8B11&&&&&&&&&&mov&&&&&edx,&dword&ptr&[ecx]&&&&&&&&&&&&&;&&指向虚基类的描述指针
0040112E&&|.&&8B4D&C4&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-3C]
&&|.&&034A&04&&&&&&&add&&&&&ecx,&dword&ptr&[edx+4]&&&&&&&&&&&;&&ecx传递clsA类this指针,但为什么未指向变量a在栈的起始地址,而指向虚基类?
&&|.&&8B45&C4&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-3C]
&&|.&&8B10&&&&&&&&&&mov&&&&&edx,&dword&ptr&[eax]
&&|.&&8B42&04&&&&&&&mov&&&&&eax,&dword&ptr&[edx+4]&&&&&&&&&&&;&&clsB类首地址至虚基类w的偏移长度
0040113C&&|.&&8B55&C4&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-3C]
0040113F&&|.&&8B0402&&&&&&&&mov&&&&&eax,&dword&ptr&[edx+eax]&&&&&&&&&;&&取虚函数地址表vtable
&&|.&&FF10&&&&&&&&&&call&&&&dword&ptr&[eax]&&&&&&&&&&&&&&&&&&;&&pb-&show();
&&|.&&8B4D&C0&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-40]
&&|.&&83C1&0C&&&&&&&add&&&&&ecx,&0C&&&&&&&&&&&&&&&&&&&&&&&&&&;&&ecx传递clsC类this指针,但为什么未指向变量a的clsC基类地址,而指向clsA类的m_b变量地址?
0040114A&&|.&&E8&&&&call&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&&pc-&clsC::show2();&&采用硬地址编码调用
0040114F&&|.&&C745&FC&FFFFF&mov&&&&&dword&ptr&[ebp-4],&-1
&&|.&&8D4D&C8&&&&&&&lea&&&&&ecx,&dword&ptr&[ebp-38]&&&&&&&&&&;&&利用ecx传递变量a的this指针
&&|.&&E8&A2020000&&&call&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&&变量a的析构函数
0040115E&&|.&&8B4D&F4&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-C]
&&|.&&64:890D&00000&mov&&&&&dword&ptr&fs:[0],&ecx
&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
0040116A&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
0040116B&&\.&&C3&&&&&&&&&&&&ret
sub&esp,38&在堆栈中为局部变量a和指针pb、pc、临时指针分配56字节.其中clsA类大小为44字节(clsA有3*4=12字节成员变量,&clsB有4字节成员变量+指向虚基类的指针4字节=8,&clsC有4字节成员变量+指向虚基类的指针4字节=8,虚基类w有2*4=8字节成员变量,虚函数有个指向vtable的虚函数表指针,占4字节,还有4个字节是“一个各个子类较虚基类偏转表”(combojiang的解释).因此一共12+8+8+8+4+4=44)
先来看一下变量a的构造函数:
&&/$&&55&&&&&&&&&&&&push&&&&ebp
&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
&&|.&&6A&FF&&&&&&&&&push&&&&-1
&&|.&&68&039E4000&&&push&&&&00409E03&&&&&&&&&&&&&&&&&&&&&&&&&;&&SE&处理程序安装
0040100A&&|.&&64:A1&0000000&mov&&&&&eax,&dword&ptr&fs:[0]
&&|.&&50&&&&&&&&&&&&push&&&&eax
&&|.&&64:&mov&&&&&dword&ptr&fs:[0],&esp
&&|.&&83EC&08&&&&&&&sub&&&&&esp,&8
0040101B&&|.&&894D&EC&&&&&&&mov&&&&&dword&ptr&[ebp-14],&ecx&&&&&&&&&&;&&变量a在栈的起始地址
0040101E&&|.&&C745&F0&00000&mov&&&&&dword&ptr&[ebp-10],&0&&&&&&&&&&&&;&&未构造虚基类
&&|.&&837D&08&00&&&&cmp&&&&&dword&ptr&[ebp+8],&0&&&&&&&&&&&&&;&&判断是否有虚基类
&&|.&&74&2E&&&&&&&&&je&&&&&&short&&&&&&&&&&&&&&&&&&&&;&&此处未跳转
0040102B&&|.&&8B45&EC&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-14]
0040102E&&|.&&C700&D0B04000&mov&&&&&dword&ptr&[eax],&&&&&&&&&;&&clsB类指向虚基类的指针
&&|.&&8B4D&EC&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-14]
&&|.&&C741&08&C8B04&mov&&&&&dword&ptr&[ecx+8],&&&&&&&;&&clsC类指向虚基类的指针
0040103E&&|.&&8B4D&EC&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-14]
&&|.&&83C1&20&&&&&&&add&&&&&ecx,&20&&&&&&&&&&&&&&&&&&&&&&&&&&;&&虚基类w位于clsA类的20字节偏移处
&&|.&&E8&C7010000&&&call&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&&虚基类w的构造函数
&&|.&&8B55&F0&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-10]
0040104C&&|.&&83CA&01&&&&&&&or&&&&&&edx,&1
0040104F&&|.&&8955&F0&&&&&&&mov&&&&&dword&ptr&[ebp-10],&edx&&&&&&&&&&;&&已构造虚基类
&&|.&&C745&FC&00000&mov&&&&&dword&ptr&[ebp-4],&0
&&|&&&6A&00&&&&&&&&&push&&&&0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&/Arg1&=&
0040105B&&|.&&8B4D&EC&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-14]&&&&&&&&&&;&|clsB类在变量a的起始地址
0040105E&&|.&&E8&BD020000&&&call&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&\clsB类的构造函数
&&|.&&C745&FC&01000&mov&&&&&dword&ptr&[ebp-4],&1
0040106A&&|.&&6A&00&&&&&&&&&push&&&&0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&/Arg1&=&
0040106C&&|.&&8B4D&EC&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-14]&&&&&&&&&&;&|
0040106F&&|.&&83C1&08&&&&&&&add&&&&&ecx,&8&&&&&&&&&&&&&&&&&&&&&&&&&&&;&|clsC类在变量a的起始地址
&&|.&&E8&&&&call&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&\clsC类的构造函数
&&|.&&8B45&EC&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-14]
0040107A&&|.&&C740&10&00000&mov&&&&&dword&ptr&[eax+10],&0&&&&&&&&&&&&;&&m_a=0
&&|.&&8B4D&EC&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-14]
&&|.&&C741&14&01000&mov&&&&&dword&ptr&[ecx+14],&1&&&&&&&&&&&&;&&m_b=1
0040108B&&|.&&8B55&EC&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-14]
0040108E&&|.&&C742&18&02000&mov&&&&&dword&ptr&[edx+18],&2&&&&&&&&&&&&;&&m_c=2
&&|.&&8B45&EC&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-14]
&&|.&&8B08&&&&&&&&&&mov&&&&&ecx,&dword&ptr&[eax]
0040109A&&|.&&8B51&04&&&&&&&mov&&&&&edx,&dword&ptr&[ecx+4]&&&&&&&&&&&;&&clsA类首地址至虚基类w的偏移长度
0040109D&&|.&&8B45&EC&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-14]
&&|.&&C7&mov&&&&&dword&ptr&[eax+edx],&&&&&;&&根据至虚基类w的偏移长度来定位类的虚函数表指针位置,改写为clsA的虚函数表指针
&&|.&&8B4D&EC&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-14]
004010AA&&|.&&8B11&&&&&&&&&&mov&&&&&edx,&dword&ptr&[ecx]
004010AC&&|.&&8B42&04&&&&&&&mov&&&&&eax,&dword&ptr&[edx+4]&&&&&&&&&&&;&&clsA类首地址至虚基类w的偏移长度
004010AF&&|.&&83E8&20&&&&&&&sub&&&&&eax,&20&&&&&&&&&&&&&&&&&&&&&&&&&&;&&这里计算结果为0,偏移大小为0?
&&|.&&8B4D&EC&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-14]
&&|.&&8B11&&&&&&&&&&mov&&&&&edx,&dword&ptr&[ecx]
&&|.&&8B4A&04&&&&&&&mov&&&&&ecx,&dword&ptr&[edx+4]&&&&&&&&&&&;&&clsA类首地址至虚基类w的偏移长度
004010BA&&|.&&8B55&EC&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-14]
004010BD&&|.&&89440A&FC&&&&&mov&&&&&dword&ptr&[edx+ecx-4],&eax&&&&&&&;&&clsA较虚基类偏转表长度为0?
&&|.&&C745&FC&FFFFF&mov&&&&&dword&ptr&[ebp-4],&-1
&&|.&&8B45&EC&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-14]
004010CB&&|.&&8B4D&F4&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-C]
004010CE&&|.&&64:890D&00000&mov&&&&&dword&ptr&fs:[0],&ecx
&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
&&\.&&C2&0400&&&&&&&ret&&&&&4
虚基类中含有虚函数这种情况下确实与以上两个实例有很大的不同。派生类实例变量a在栈中的分布并非像实例一中所描述的虚函数地址表vtable在整个空间的第一个DWORD位置。而变量a的第一个DWORD位置存放的是基类clsB(即clsB类的指向虚基类的指针)。
从反汇编的代码中可见,&虚基类w位于clsA类的0x20字节偏移处,而整个类的虚函数地址表vtable存放在虚基类w的第一个DWORD空间中(即位于clsA类的0x20字节偏移处)。从这点上看貌似这个实例是前面介绍的二个实例的结合,但却与前面二个实例的结构有很大的不同。
下面跟进虚基类w的构造函数看下:
&&/$&&55&&&&&&&&&&&&push&&&&ebp
&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
&&|.&&51&&&&&&&&&&&&push&&&&ecx
&&|.&&894D&FC&&&&&&&mov&&&&&dword&ptr&[ebp-4],&ecx
&&|.&&8B45&FC&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-4]
0040121A&&|.&&C700&D8B04000&mov&&&&&dword&ptr&[eax],&&&&&&&&&;&&虚基类w的虚函数表指针
&&|.&&8B4D&FC&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-4]
&&|.&&C741&08&00000&mov&&&&&dword&ptr&[ecx+8],&0&&&&&&&&&&&&&;&&m_w2=0
0040122A&&|.&&8B55&FC&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-4]
0040122D&&|.&&C742&04&00000&mov&&&&&dword&ptr&[edx+4],&0&&&&&&&&&&&&&;&&m_w1=0
&&|.&&8B45&FC&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-4]
&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
0040123A&&\.&&C3&&&&&&&&&&&&ret
这里的代码很简单,先是写入虚基类w的虚函数表指针、初始化虚基类成员变量。因此可见虚基类w的大小为0xC个字节。位于clsA类结构的0x20字节偏移处。
下面是clsB类的构造函数:
&&/$&&55&&&&&&&&&&&&push&&&&ebp
&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
&&|.&&83EC&08&&&&&&&sub&&&&&esp,&8
&&|.&&894D&F8&&&&&&&mov&&&&&dword&ptr&[ebp-8],&ecx&&&&&&&&&&&;&&clsB类的起始地址
&&|.&&C745&FC&00000&mov&&&&&dword&ptr&[ebp-4],&0
&&|.&&837D&08&00&&&&cmp&&&&&dword&ptr&[ebp+8],&0&&&&&&&&&&&&&;&&判断是否有虚基类
&&|.&&74&1D&&&&&&&&&je&&&&&&short&&&&&&&&&&&&&&&&&&&&;&&无,跳走
&&|.&&8B45&F8&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-8]
&&|.&&C700&F8B04000&mov&&&&&dword&ptr&[eax],&
0040133F&&|.&&8B4D&F8&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-8]
&&|.&&83C1&0C&&&&&&&add&&&&&ecx,&0C
&&|.&&E8&C6FEFFFF&&&call&&&&
0040134A&&|.&&8B4D&FC&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-4]
0040134D&&|.&&83C9&01&&&&&&&or&&&&&&ecx,&1
&&|.&&894D&FC&&&&&&&mov&&&&&dword&ptr&[ebp-4],&ecx
&&|&&&8B55&F8&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-8]&&&&&&&&&&&;&&jmp&here
&&|.&&8B02&&&&&&&&&&mov&&&&&eax,&dword&ptr&[edx]&&&&&&&&&&&&&;&&指向虚基类的描述指针
&&|.&&8B48&04&&&&&&&mov&&&&&ecx,&dword&ptr&[eax+4]&&&&&&&&&&&;&&clsB类首地址至虚基类w的偏移长度
0040135B&&|.&&8B55&F8&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-8]
0040135E&&|.&&C7040A&F0B040&mov&&&&&dword&ptr&[edx+ecx],&&&&&;&&根据至虚基类w的偏移长度来定位类的虚函数表指针位置,改写为clsB的虚函数表指针
&&|.&&8B45&F8&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-8]
&&|.&&8B08&&&&&&&&&&mov&&&&&ecx,&dword&ptr&[eax]
0040136A&&|.&&8B51&04&&&&&&&mov&&&&&edx,&dword&ptr&[ecx+4]&&&&&&&&&&&;&&clsB类首地址至虚基类w的偏移长度
0040136D&&|.&&83EA&0C&&&&&&&sub&&&&&edx,&0C&&&&&&&&&&&&&&&&&&&&&&&&&&;&&计算clsB类较虚基类偏移长度(相对长度,不包含clsB类大小和偏移表结构大小)
&&|.&&8B45&F8&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-8]
&&|.&&8B08&&&&&&&&&&mov&&&&&ecx,&dword&ptr&[eax]
&&|.&&8B41&04&&&&&&&mov&&&&&eax,&dword&ptr&[ecx+4]&&&&&&&&&&&;&&clsB类首地址至虚基类w的偏移长度
&&|.&&8B4D&F8&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-8]
0040137B&&|.&&895401&FC&&&&&mov&&&&&dword&ptr&[ecx+eax-4],&edx&&&&&&&;&&各个子类较虚基类偏转表.存放上面计算的结果(clsB至虚基类偏移大小)
0040137F&&|.&&8B55&F8&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-8]
&&|.&&C742&04&00000&mov&&&&&dword&ptr&[edx+4],&0&&&&&&&&&&&&&;&&m_b=0
&&|.&&8B45&F8&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-8]
0040138C&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
0040138E&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
0040138F&&\.&&C2&0400&&&&&&&ret&&&&&4
这里比较复杂。根据汇编注释,从开始看。首先是获取指向虚基类的描述指针。这个指针所指向的结构内容为:|&00&00&00&00&20&00&00&00
第一个DWORD为0,第2个DWORD表示基类clsB的地址至虚基类w地址的偏移长度为0x20字节。(从前面汇编代码add&ecx,&20也能看出虚基类至变量a起始地址长度0x20字节)
之后根据获得的至虚基类w的偏移长度来定位类的虚函数表指针位置,并改写为clsB的虚函数表指针。clsB的虚函数表指针指向,看下地址的所指向结构的数据:&|&B0&1C&40&00&E0&1C&40&00(clsB共有2个函数(包含继承),这里有两个指针)
看下00401CB0所指向的汇编代码:
00401CB0&&&.&&2B49&FC&&&&&&&sub&&&&&ecx,&dword&ptr&[ecx-4]&&&&&&&&&&&;&&this指针减去该子类较虚基类偏转表偏移长度?
00401CB3&&&.&&E9&&&&jmp&&&&&00401CC0
00401CB8&&&&&&CC&&&&&&&&&&&&int3
00401CB9&&&&&&CC&&&&&&&&&&&&int3
00401CBA&&&&&&CC&&&&&&&&&&&&int3
00401CBB&&&&&&CC&&&&&&&&&&&&int3
00401CBC&&&&&&CC&&&&&&&&&&&&int3
00401CBD&&&&&&CC&&&&&&&&&&&&int3
00401CBE&&&&&&CC&&&&&&&&&&&&int3
00401CBF&&&&&&CC&&&&&&&&&&&&int3
00401CC0&&/&&&55&&&&&&&&&&&&push&&&&ebp
00401CC1&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
00401CC3&&|.&&51&&&&&&&&&&&&push&&&&ecx
00401CC4&&|.&&894D&FC&&&&&&&mov&&&&&dword&ptr&[ebp-4],&ecx
00401CC7&&|.&&68&D8D04000&&&push&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&&ASCII&&I'm&in&clsB&Class.&
00401CCC&&|.&&68&F8DD4000&&&push&&&&0040DDF8
00401CD1&&|.&&E8&1AF8FFFF&&&call&&&&
00401CD6&&|.&&83C4&08&&&&&&&add&&&&&esp,&8
00401CD9&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
00401CDB&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
00401CDC&&\.&&C3&&&&&&&&&&&&ret
第一行代码后面再分析,第二行直接jmp到clsB::show()函数中
虚函数表下一个指针指向00401CE0,看下所指向的汇编代码:
00401CE0&&&.&&2B49&FC&&&&&&&sub&&&&&ecx,&dword&ptr&[ecx-4]&&&&&&&&&&&;&&this指针减去该子类较虚基类偏转表偏移长度?
00401CE3&&&.&&E9&&&&jmp&&&&&00401CF0
00401CE8&&&&&&CC&&&&&&&&&&&&int3
00401CE9&&&&&&CC&&&&&&&&&&&&int3
00401CEA&&&&&&CC&&&&&&&&&&&&int3
00401CEB&&&&&&CC&&&&&&&&&&&&int3
00401CEC&&&&&&CC&&&&&&&&&&&&int3
00401CED&&&&&&CC&&&&&&&&&&&&int3
00401CEE&&&&&&CC&&&&&&&&&&&&int3
00401CEF&&&&&&CC&&&&&&&&&&&&int3
00401CF0&&/&&&55&&&&&&&&&&&&push&&&&ebp
00401CF1&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
00401CF3&&|.&&51&&&&&&&&&&&&push&&&&ecx
00401CF4&&|.&&894D&FC&&&&&&&mov&&&&&dword&ptr&[ebp-4],&ecx
00401CF7&&|.&&68&ECD04000&&&push&&&&0040D0EC&&&&&&&&&&&&&&&&&&&&&&&&&;&&ASCII&&I'm&in&clsB&Class2.&
00401CFC&&|.&&68&F8DD4000&&&push&&&&0040DDF8
00401D01&&|.&&E8&EAF7FFFF&&&call&&&&
00401D06&&|.&&83C4&08&&&&&&&add&&&&&esp,&8
00401D09&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
00401D0B&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
00401D0C&&\.&&C3&&&&&&&&&&&&ret
同样是clsB::show2()函数汇编代码。
clsB类改写虚函数表vtable指针后。下面是与前二个实例与众不同的地方。首先根据指向虚基类的描述指针取出clsB类首地址至虚基类w的偏移长度(这里为0x20),然后减去0xC,后将该值(0x14)存放到虚基类w存储位置的前一个DWORD空间中。不知这样说大家会不会明白,参照文章最后的结构图就会明白了。这个结构的作用我也不是很明白。combojiang大哥解释是“各个子类较虚基类偏转表”,这里的分析也就使用了这个术语。还请各位DX解释一下具体作用。谢谢。
(PS我简单测试分析了一下,减去的那个0xC好像是clsB类大小+“各个子类较虚基类偏转表”结构大小(4字节),8+4=0xC。不知道我的解释是否正确,还请各位帮助讲一下)
最后是clsB类的成员变量初始化赋值操作。m_b=0
clsB构造函数结束后,接着是clsC的构造函数:
&&/$&&55&&&&&&&&&&&&push&&&&ebp
&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
&&|.&&83EC&08&&&&&&&sub&&&&&esp,&8
&&|.&&894D&F8&&&&&&&mov&&&&&dword&ptr&[ebp-8],&ecx&&&&&&&&&&&;&&clsC类的起始地址
&&|.&&C745&FC&00000&mov&&&&&dword&ptr&[ebp-4],&0
&&|.&&837D&08&00&&&&cmp&&&&&dword&ptr&[ebp+8],&0&&&&&&&&&&&&&;&&判断是否有虚基类
&&|.&&74&1D&&&&&&&&&je&&&&&&short&&&&&&&&&&&&&&&&&&&&;&&无,跳走
&&|.&&8B45&F8&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-8]
&&|.&&C700&E8B04000&mov&&&&&dword&ptr&[eax],&
004012BF&&|.&&8B4D&F8&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-8]
&&|.&&83C1&0C&&&&&&&add&&&&&ecx,&0C
&&|.&&E8&46FFFFFF&&&call&&&&
004012CA&&|.&&8B4D&FC&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-4]
004012CD&&|.&&83C9&01&&&&&&&or&&&&&&ecx,&1
&&|.&&894D&FC&&&&&&&mov&&&&&dword&ptr&[ebp-4],&ecx
&&|&&&8B55&F8&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-8]&&&&&&&&&&&;&&jmp&here
&&|.&&8B02&&&&&&&&&&mov&&&&&eax,&dword&ptr&[edx]&&&&&&&&&&&&&;&&指向虚基类的描述指针
&&|.&&8B48&04&&&&&&&mov&&&&&ecx,&dword&ptr&[eax+4]&&&&&&&&&&&;&&clsC类首地址至虚基类w的偏移长度
004012DB&&|.&&8B55&F8&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-8]
004012DE&&|.&&C7040A&E0B040&mov&&&&&dword&ptr&[edx+ecx],&&&&&;&&根据至虚基类w的偏移长度来定位类的虚函数表指针位置,改写为clsC的虚函数表指针
&&|.&&8B45&F8&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-8]
&&|.&&8B08&&&&&&&&&&mov&&&&&ecx,&dword&ptr&[eax]
004012EA&&|.&&8B51&04&&&&&&&mov&&&&&edx,&dword&ptr&[ecx+4]&&&&&&&&&&&;&&clsC类首地址至虚基类w的偏移长度
004012ED&&|.&&83EA&0C&&&&&&&sub&&&&&edx,&0C&&&&&&&&&&&&&&&&&&&&&&&&&&;&&计算clsC类较虚基类偏移长度(相对长度,不包含clsC类大小和偏移表结构大小)
&&|.&&8B45&F8&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-8]
&&|.&&8B08&&&&&&&&&&mov&&&&&ecx,&dword&ptr&[eax]
&&|.&&8B41&04&&&&&&&mov&&&&&eax,&dword&ptr&[ecx+4]&&&&&&&&&&&;&&clsC类首地址至虚基类w的偏移长度
&&|.&&8B4D&F8&&&&&&&mov&&&&&ecx,&dword&ptr&[ebp-8]
004012FB&&|.&&895401&FC&&&&&mov&&&&&dword&ptr&[ecx+eax-4],&edx&&&&&&&;&&各个子类较虚基类偏转表.存放上面计算的结果(clsC至虚基类偏移大小)
004012FF&&|.&&8B55&F8&&&&&&&mov&&&&&edx,&dword&ptr&[ebp-8]
&&|.&&C742&04&00000&mov&&&&&dword&ptr&[edx+4],&0&&&&&&&&&&&&&;&&m_c=0
&&|.&&8B45&F8&&&&&&&mov&&&&&eax,&dword&ptr&[ebp-8]
0040130C&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
0040130E&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
0040130F&&\.&&C2&0400&&&&&&&ret&&&&&4
不难看出clsC的构造函数与clsB类的构造函数大同小异。同样首先是获取指向虚基类的描述指针。这个指针所指向的结构内容为:&|&00&00&00&00&18&00&00&00
第一个DWORD为0,第2个DWORD表示基类clsC的地址至虚基类w地址的偏移长度为0x18字节(参照文章后面的类结构图)。之后根据获得的至虚基类w的偏移长度来定位类的虚函数表指针位置,并改写为clsC的虚函数表指针。clsC的虚函数表指针指向,看下地址的所指向结构的数据:&|&70&1D&40&00&A0&1D&40&00(clsC共有2个函数(包含继承),这里有两个指针)
看下00401D70所指向的汇编代码:
00401D70&&&.&&2B49&FC&&&&&&&sub&&&&&ecx,&dword&ptr&[ecx-4]
00401D73&&&.&&E9&&&&jmp&&&&&00401D80
00401D78&&&&&&CC&&&&&&&&&&&&int3
00401D79&&&&&&CC&&&&&&&&&&&&int3
00401D7A&&&&&&CC&&&&&&&&&&&&int3
00401D7B&&&&&&CC&&&&&&&&&&&&int3
00401D7C&&&&&&CC&&&&&&&&&&&&int3
00401D7D&&&&&&CC&&&&&&&&&&&&int3
00401D7E&&&&&&CC&&&&&&&&&&&&int3
00401D7F&&&&&&CC&&&&&&&&&&&&int3
00401D80&&/&&&55&&&&&&&&&&&&push&&&&ebp
00401D81&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
00401D83&&|.&&51&&&&&&&&&&&&push&&&&ecx
00401D84&&|.&&894D&FC&&&&&&&mov&&&&&dword&ptr&[ebp-4],&ecx
00401D87&&|.&&68&28D14000&&&push&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&&ASCII&&I'm&in&clsC&Class.&
00401D8C&&|.&&68&F8DD4000&&&push&&&&0040DDF8
00401D91&&|.&&E8&5AF7FFFF&&&call&&&&
00401D96&&|.&&83C4&08&&&&&&&add&&&&&esp,&8
00401D99&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
00401D9B&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
00401D9C&&\.&&C3&&&&&&&&&&&&ret
地址指向clsC::show()函数中。
虚函数表下一个指针指向00401DA0,看下所指向的汇编代码:
00401DA0&&&.&&2B49&FC&&&&&&&sub&&&&&ecx,&dword&ptr&[ecx-4]
00401DA3&&&.^&E9&38F6FFFF&&&jmp&&&&&
&&/$&&55&&&&&&&&&&&&push&&&&ebp
&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
&&|.&&51&&&&&&&&&&&&push&&&&ecx
&&|.&&894D&FC&&&&&&&mov&&&&&dword&ptr&[ebp-4],&ecx
&&|.&&68&C4D04000&&&push&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&&ASCII&&I'm&in&clsC&Class2.&
004013EC&&|.&&68&F8DD4000&&&push&&&&0040DDF8
&&|.&&E8&FA000000&&&call&&&&
&&|.&&83C4&08&&&&&&&add&&&&&esp,&8
&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
004013FB&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
004013FC&&\.&&C3&&&&&&&&&&&&ret
同理是clsC::show2()函数汇编代码。
clsC类同样改写虚函数表vtable指针,使其指向类自己的函数。下面同样使用了clsC类较虚基类偏转长度改写了“各个子类较虚基类偏转表”结构。这里将这个结构改写为0xC(0x18-0xC。同样我分析的减去0xC为clsC类大小+“各个子类较虚基类偏转表”结构大小(4字节)&,8+4=0xC。不知道我的解释是否正确,还请各位帮助讲一下)
最后是clsC类的成员变量初始化赋值操作。m_c=0
clsB和clsC的构造函数结束后,下面回到clsA的构造函数继续分析:
先是初始化了clsA类的成员变量(m_b(1),m_c(2),m_a(0)),这里强调一下,使用类的构造函数成员初始化列表对成员变量的初始化顺为成员变量在类的定义顺序,而不是初始化列表中的顺序(即顺序为m_a、m_b、m_c)。而类的继承(class&clsA:public&clsB,public&clsC),在类的结构体内的顺序为类声明的先后顺序(即先是clsB后clsC)。这两点的顺序是不同的。
派生类clsA最终要改写虚函数地址表vtable指针(同样根据至虚基类w的偏移长度来定位类的虚函数表指针位置,改写为clsA的虚函数表指针),完成最后的虚函数特性。
clsA的虚函数表指针指向,看下地址的所指向结构的数据:&|&10&1D&40&00&40&1D&40&00(clsA共有2个函数(包含继承),这里有两个指针)
看下00401D10所指向的汇编代码:
00401D10&&&.&&2B49&FC&&&&&&&sub&&&&&ecx,&dword&ptr&[ecx-4]&&&&&&&&&&&;&&this指针减去该子类较虚基类偏转表偏移长度?
00401D13&&&.&&E9&&&&jmp&&&&&00401D20
00401D18&&&&&&CC&&&&&&&&&&&&int3
00401D19&&&&&&CC&&&&&&&&&&&&int3
00401D1A&&&&&&CC&&&&&&&&&&&&int3
00401D1B&&&&&&CC&&&&&&&&&&&&int3
00401D1C&&&&&&CC&&&&&&&&&&&&int3
00401D1D&&&&&&CC&&&&&&&&&&&&int3
00401D1E&&&&&&CC&&&&&&&&&&&&int3
00401D1F&&&&&&CC&&&&&&&&&&&&int3
00401D20&&/&&&55&&&&&&&&&&&&push&&&&ebp
00401D21&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
00401D23&&|.&&51&&&&&&&&&&&&push&&&&ecx
00401D24&&|.&&894D&FC&&&&&&&mov&&&&&dword&ptr&[ebp-4],&ecx
00401D27&&|.&&68&00D14000&&&push&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&&ASCII&&I'm&in&clsA&Class.&
00401D2C&&|.&&68&F8DD4000&&&push&&&&0040DDF8
00401D31&&|.&&E8&BAF7FFFF&&&call&&&&
00401D36&&|.&&83C4&08&&&&&&&add&&&&&esp,&8
00401D39&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
00401D3B&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
00401D3C&&\.&&C3&&&&&&&&&&&&ret
地址指向clsA::show()函数中。
虚函数表下一个指针指向00401D40,看下所指向的汇编代码:
00401D40&&&.&&2B49&FC&&&&&&&sub&&&&&ecx,&dword&ptr&[ecx-4]&&&&&&&&&&&;&&this指针减去该子类较虚基类偏转表偏移长度?
00401D43&&&.&&E9&&&&jmp&&&&&00401D50
00401D48&&&&&&CC&&&&&&&&&&&&int3
00401D49&&&&&&CC&&&&&&&&&&&&int3
00401D4A&&&&&&CC&&&&&&&&&&&&int3
00401D4B&&&&&&CC&&&&&&&&&&&&int3
00401D4C&&&&&&CC&&&&&&&&&&&&int3
00401D4D&&&&&&CC&&&&&&&&&&&&int3
00401D4E&&&&&&CC&&&&&&&&&&&&int3
00401D4F&&&&&&CC&&&&&&&&&&&&int3
00401D50&&/&&&55&&&&&&&&&&&&push&&&&ebp
00401D51&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp
00401D53&&|.&&51&&&&&&&&&&&&push&&&&ecx
00401D54&&|.&&894D&FC&&&&&&&mov&&&&&dword&ptr&[ebp-4],&ecx
00401D57&&|.&&68&14D14000&&&push&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;&&ASCII&&I'm&in&clsA&Class2.&
00401D5C&&|.&&68&F8DD4000&&&push&&&&0040DDF8
00401D61&&|.&&E8&8AF7FFFF&&&call&&&&
00401D66&&|.&&83C4&08&&&&&&&add&&&&&esp,&8
00401D69&&|.&&8BE5&&&&&&&&&&mov&&&&&esp,&ebp
00401D6B&&|.&&5D&&&&&&&&&&&&pop&&&&&ebp
00401D6C&&\.&&C3&&&&&&&&&&&&ret
同理是clsA::show2()函数汇编代码。
clsA类最后使用了clsA类较虚基类偏转长度改写了“各个子类较虚基类偏转表”结构。这里最终将这个结构改写为0x0(0x20-0x20。没算明白,请高手指教!@#¥%……&×…)。clsA类较虚基类偏转表偏转长度为0?
整个类的构造函数分析完了。下面看下这个构造函数对变量a在栈中的赋值情况:
0012FF48&&&&&&&&&&&|指向虚基类w的描述指针
0012FF4C&&&&&&&&&&&|clsB成员变量m_b
0012FF50&&&&&&&&&&&|指向虚基类w的描述指针
0012FF54&&&&&&&&&&&|clsC成员变量m_c
0012FF58&&&&&&&&&&&|clsA成员变量m_a
0012FF5C&&&&&&&&&&&|clsA成员变量m_b
0012FF60&&&&&&&&&&&|clsA成员变量m_c
0012FF64&&&&&&&&&&&|各个子类较虚基类偏转表
0012FF68&&&&&&&&&&&|虚函数地址表vtable指针
0012FF6C&&&&&&&&&&&|虚基类w成员变量m_w1
0012FF70&&&&&&&&&&&|虚基类w成员变量m_w2
这里有三个地方不明白。请大家帮助解释一下
第一:回到main函数,在地址处调用pb-&show();时,按理说ecx寄存器应该保存被调用类的this指针(这里为clsA),但为什么不是0012FF48,而指向虚基类的地址0012FF68?这里的this指针难道从虚基类位置开始?
第二:回到main函数,在地址处调用pb-&show();,转到如下代码处:
00401D10&.&2B49&FC&sub&ecx,&dword&ptr&[ecx-4]
00401D13&.&E9&&jmp&00401D20
修改了ecx指针,因为派生类最后将“各个子类较虚基类偏转表”结构内容赋为0,因此这条指令对ecx不做修改。我想这条指令可能跟“各个子类较虚基类偏转表”这个结构有关吧。包括构造函数对该结构的赋值。。。还是请高手帮忙给解释一下吧。
第三:回到main函数,在地址0040114A处调用pc-&clsC::show2();时,ecx的内容(this指针)为什么是0012FF5C(即指向clsA成员变量m_b)?我认为应该是0012FF50(指向变量a的clsC基类)。
这里的结构(虚基类中包含虚函数)与前二个例子最大的区别主要有二点。
第一:否定了虚函数地址表vtable指针在整个类结构的第一个DWORD位置。在虚基类中包含虚函数情况下,虚函数地址表vtable指针存放在虚基类的第一个DWORD位置。
第二:在虚基类中包含虚函数类层次结构中,多了一个“各个子类较虚基类偏转表”这个结构(这个结构我还不是十分了解。还请教各位高手)。这个结构位于派生类和虚基类之间,占4字节空间。
最后带着问题,把整个clsA类在栈的分配结构图画下来做为这次的学习总结:}

我要回帖

更多关于 classa 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信