视觉C 中的Devirtualization
Devirtualization in visual c++
visual C devirtualial devirtualial deviratualize pure Class的函数仅具有一个实现?例如:
class ICar
{
public:
virtual void Break() = 0;
};
class CarImpl : public ICar
{
public:
virtual void Break(){ .... }
};
op问题自然分解为3个问题:
- vc 2010会做描述的devirtualization-答案是:否
- 它可以做到 - 答案是:是理论上可能是在某些情况下完成。
- 为什么VC 不这样做。 - 我们只能推测...
这是详细信息:
1。是通过VC
进行的优化要证明未完成此优化,我们需要在Project Properties/Configuration属性/C/C/C /输出文件中启用汇编器语言列表:将汇编器输出设置为"带有源代码的汇编"(/fas)。p>这是OP的稍微修改的C 代码(我将ICAR从抽象类更改为正常,它不会改变问题的要旨):
#include "stdafx.h"
class ICar
{
public:
virtual void Accelerate(){printf("%s", "an");};
virtual void Break(){printf("%s", "bn");};
};
class CarImpl : public ICar
{
public:
virtual void Accelerate(){ printf("%s", "acceleraten"); }
virtual void Break(){ printf("%s", "breakn"); }
void Fly() { printf("%s", "flyn"); }
};
int _tmain(int argc, _TCHAR* argv[])
{
ICar *pCar = new CarImpl();
pCar->Break();
CarImpl *pCarImpl = new CarImpl();
pCarImpl->Fly();
CarImpl carImpl;
carImpl.Break();
carImpl.Fly();
return 0;
}
首先,(注意1 )让我们注意carImpl.Break();
不使用虚拟函数。这不是优化的结果 - 它是C 的特征:如果在编译过程中已知对象的类型,则不会使用虚拟函数的机理。仅在涉及指针或参考时,使用虚拟函数的机制。
第二,让我们启用优化/O2,然后查看为pCar->Break();
(虚拟方法)和pCarImpl->Fly();
(非虚拟方法)生成的汇编程序。
呼叫打破()我们将看到:
; 24 : pCar->Break();
mov edx, DWORD PTR [eax]
mov ecx, eax
mov eax, DWORD PTR [edx+4]
call eax
eax包含一个指向Carimpl对象的指针(从此处未显示的汇编器的前几行可以清楚地看出)。在第一个MOV指令中,Carimpl对象的第一个DWORD加载到EDX中(对象的第一个dword通常是VTBL的地址),然后将Carimpl的this
加载到ECX中(这对我们来说并不重要),则是DWORD从偏移4到EDX点(虚拟函数表中的第二个函数)的点,然后加载到EAX中,然后进行调用。
如果fly(),我们将看到:
; 27 : pCarImpl->Fly();
push OFFSET ??_C@_04PPJAHJOB@fly?6?$AA@
push OFFSET ??_C@_02DKCKIIND@?$CFs?$AA@
call _printf
这只是将printf与传递给它的两个参数的融合。
因此,显然在Break()的情况下不会优化VTable的使用。
2。可以完成这样的优化
在本金中,它可以优化。我在M.Ellis,B。Stroustrup,Addison-Wesley 1990的" C 参考手册"中找到了以下陈述:第10.2章(我有翻译中的这本书,我正在翻译回英语:--)所以可能不是Stroustoup的确切措辞。)
当编译时间知道确切的对象的确切类型时,无需虚拟函数机理。相反,实现可以生成类成员函数的普通调用。(DK:我们的代码中的Carimpl.break()案例,请参阅我的注释1)...当通过指针或参考调用虚拟函数时,可能在对象的实际类型上可能是静态的,因此应使用虚拟函数的机制。具有足够了解控制流量的编译器即使在某些情况下通过BP在以下代码中通过BP进行调用也可以删除对虚拟函数的调用:
struct base {
virtual void vf1();
}
class derived : public base{
public:
void vf1();
}
void g()
{
derived d;
base* bp = &d;
bp->vf1();
}
...内联虚拟功能具有完全有意义的意义,并且经常使用。自然地,内部仅用于将内联函数应用于已知类型对象的地方。(DK:我认为这里B. Stroustrup也指我们的Carimpl.break();即Note1中描述的案例)。
3。为什么不完成
尽管这不是在OP中从字面上提出的,但这也许是一个隐藏的问题。我同意亚历克斯·科恩(Alex Cohn)的一项评论(言论很好):
可以,但事实并非如此。这可能不够经常发生,无法证明可靠地优化此类呼叫所需的资源。
编辑:这个答案被我的第二个答案所掩盖,这是我2012-10-20的第二个答案。我没有将其删除以保留评论。
VC 不可能,因为其他派生类可以链接到已编译的DLL或EXE模块。
- 没有找到相关文章