java基类能调用虚函数_C++中构造函数能调用虚函数吗?(答案是语法可以,输出错误),但Java里居然可以...

环境:XPSP3 VS2005

今天黑总给应聘者出了一个在C++的构造函数中调用虚函数的问题,具体的题目要比标题复杂,大体情况可以看如下的代码:

class Base

{

public:

Base()

{

Fuction();

}

virtual void Fuction()

{

cout <

}

};

class A : public Base

{

public:

A()

{

Fuction();

}

virtual void Fuction()

{

cout <

}

};

// 这样定义一个A的对象,会输出什么?

A a;

首先回答标题的问题,调用当然是没有问题的,但是获得的是你想要的结果吗?或者说你想要什么样的结果?

有人说会输出:

A::Fuction

A::Fuction

如果是这样,首先我们回顾下C++对象模型里面的构造顺序,在构造一个子类对象的时候,首先会构造它的基类,如果有多层继承关系,实际上会从最顶层的基类逐层往下构造(虚继承、多重继承这里不讨论),如果是按照上面的情形进行输出的话,那就是说在构造Base的时候,也就是在Base的构造函数中调用Fuction的时候,调用了子类A的Fuction,而实际上A还没有开始构造,这样函数的行为就是完全不可预测的,因此显然不是这样,实际的输出结果是:

Base::Fuction

A::Fuction

据说在Java中是上一种输出(感觉有点匪夷所思)。

我们来单步看一下到底发生了什么?在A的构造函数里面首先会去调用Base的构造函数,Base的构造函数如下:

class Base

{

public:

Base()

00411600  push        ebp

00411601  mov         ebp,esp

00411603  sub         esp,0CCh

00411609  push        ebx

0041160A  push        esi

0041160B  push        edi

0041160C  push        ecx

0041160D  lea         edi,[ebp-0CCh]

00411613  mov         ecx,33h

00411618  mov         eax,0CCCCCCCCh

0041161D  rep stos    dword ptr es:[edi]

0041161F  pop         ecx

00411620  mov         dword ptr [ebp-8],ecx

00411623  mov         eax,dword ptr [this]

00411626  mov         dword ptr [eax],offset Base::`vftable‘ (41770Ch) {

Fuction();

0041162C  mov         ecx,dword ptr [this]

0041162F  call        Base::Fuction (4111A9h)

}

00411634  mov         eax,dword ptr [this]

00411637  pop         edi

00411638  pop         esi

00411639  pop         ebx

0041163A  add         esp,0CCh

00411640  cmp         ebp,esp

00411642  call        @ILT+460(__RTC_CheckEsp) (4111D1h)

00411647  mov         esp,ebp

00411649  pop         ebp

0041164A  ret

从单步跟踪来看,注意黑色加粗的那部分汇编代码,ecx中存放的是对象的地址(0x0012ff60,我的机器上的情况看下图,有图有真相),首先是设置vtable的地址到对象的前四个字节(不同的编译器可能不同),然后就直接调用了Base::Fuction函数,并没有走虚机制,而我们此时看虚表中的状态,虚表已经填充的是0x4111a9,注意虚表的地址0x0041770c,而此时对象地址0x0012FF60前四个字节存放的正是0x0041770c。

0_1314719334fQUG.gif

继续跟踪,流程又回到A的构造函数中,再次注意加粗部分的代码,从基类Base的构造函数返回后,在A的构造函数中,重设了虚表指针,现在的虚表指针是(0x417700h),同样调用Fuction的时候直接调用了A::Fuction函数,并没有使用虚机制,而且此时虚表0x417700h指向的位置存放的0x41110e正是A::Fuction的地址。

0_131472018225lh.gif

class A : public Base

{

public:

A()

00411590  push        ebp

00411591  mov         ebp,esp

00411593  sub         esp,0CCh

00411599  push        ebx

0041159A  push        esi

0041159B  push        edi

0041159C  push        ecx

0041159D  lea         edi,[ebp-0CCh]

004115A3  mov         ecx,33h

004115A8  mov         eax,0CCCCCCCCh

004115AD  rep stos    dword ptr es:[edi]

004115AF  pop         ecx

004115B0  mov         dword ptr [ebp-8],ecx

004115B3  mov         ecx,dword ptr [this]

004115B6  call        Base::Base (411140h)

004115BB  mov         eax,dword ptr [this]

004115BE  mov         dword ptr [eax],offset A::`vftable‘ (417700h) {

Fuction();

004115C4  mov         ecx,dword ptr [this]

004115C7  call        A::Fuction (41110Eh) }

004115CC  mov         eax,dword ptr [this]

004115CF  pop         edi

004115D0  pop         esi

004115D1  pop         ebx

004115D2  add         esp,0CCh

004115D8  cmp         ebp,esp

004115DA  call        @ILT+460(__RTC_CheckEsp) (4111D1h)

004115DF  mov         esp,ebp

004115E1  pop         ebp

004115E2  ret

其实事情就是这么简单。

http://blog.csdn.net/magictong/article/details/6734241

原文:http://www.cnblogs.com/findumars/p/7123497.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值