视觉C 中的Devirtualization

Devirtualization in visual c++

本文关键字:Devirtualization 中的 视觉      更新时间:2023-10-16

visual C devirtualial devirtualial deviratualize pure Class的函数仅具有一个实现?例如:

class ICar
{
public:
virtual void Break() = 0;
};
class CarImpl : public ICar
{
public:
virtual void Break(){ .... }
};

op问题自然分解为3个问题:

  1. vc 2010会做描述的devirtualization-答案是:
  2. 它可以做到 - 答案是:理论上可能是在某些情况下完成。
  3. 为什么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模块。

相关文章:
  • 没有找到相关文章