gpt4 book ai didi

c++ - Visual C++ 中的去虚拟化

转载 作者:太空狗 更新时间:2023-10-29 19:59:29 24 4
gpt4 key购买 nike

visual c++ 是否为只有一个实现的纯类去虚拟化一个函数?例如:

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

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

最佳答案

OP 问题自然分为 3 个问题:

  1. VC++ 2010 是否执行所描述的去虚拟化 - 答案是:
  2. 它能做到吗 - 答案是:理论上它本可以在某些情况下完成。
  3. 为什么 VC++ 不这样做。 - 我们只能推测...

详情如下:

1。这样的优化是VC++做的吗

为了证明此优化未完成,我们需要在项目属性/配置属性/C/C++/输出文件中启用汇编语言列表:将汇编输出设置为“使用源代码汇编”(/FAs)。

这是来自 OP 的略微修改的 C++ 代码(我将 ICar 从抽象类更改为普通类,它不会改变问题的要点):

#include "stdafx.h"

class ICar
{
public:
virtual void Accelerate(){printf("%s", "a\n");};
virtual void Break(){printf("%s", "b\n");};
};

class CarImpl : public ICar
{
public:
virtual void Accelerate(){ printf("%s", "accelerate\n"); }
virtual void Break(){ printf("%s", "break\n"); }
void Fly() { printf("%s", "fly\n"); }
};

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(); 生成的汇编程序(非虚拟方法)。

对于 Break() 的调用,我们将看到:

; 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中(这个不重要)对于我们来说),然后将EDX指向的点(虚函数表中的第二个函数)偏移量为4的dword加载到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 年的“The Annotated C++ Reference Manual”中找到了以下声明:第 10.2 章(我有这本书的翻译,我正在翻译回英文 :-) 所以它可能不是 Stroustroup 的确切措辞。)

如果对象的确切类型在编译时已知,则不需要虚函数机制。相反,实现可以生成类成员函数的普通调用。 (DK:我们代码中 carImpl.Break() 的情况,请参见我的注释 1)...当通过指针或引用调用虚函数时,可能无法静态知道对象的实际类型,因此应使用虚函数机制。对控制流有足够了解的编译器甚至可以在某些情况下放弃对虚函数的调用,例如在以下代码中通过 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 的评论之一(说得好):

它可以,但事实并非如此。可能这种情况发生的频率不够高,不足以证明可靠地优化此类调用所需的资源是合理的。

关于c++ - Visual C++ 中的去虚拟化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12962820/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com