我希望编译器能够静态解析对虚函数的函数调用,如果在编译时已知类的类型(例如,如果没有通过引用或指针使用类实例,如图所示)案例1)如下)。
但是,我观察到Visual Studio 2010的C ++编译器有一种奇怪的行为,我想知道编译器是否有任何理由不在类的实例中静态绑定对“正确”虚函数的调用虚函数是通过引用访问的结构中的成员。
我是否希望编译器在下面的案例2中静态绑定对f()的调用?即使a
是A
而不是A&
,cr的“参考”是否会以某种方式传播到cr.a?
struct A
{
virtual void f() ;
virtual ~A() ;
};
struct B : A
{
virtual void f() ;
virtual ~B() ;
};
struct C {
A a ;
B b ;
};
C & GetACRef() ;
void test()
{
// Case 1) The following calls to f() are statically bound i.e.
// f() is called without looking up the virtual function ptr.
C c ;
c.a.f() ;
c.b.f() ;
A a ;
a.f() ;
// Case 2) The following calls to f() go through the dynamic dispatching
// virtual function lookup code. You can check if you generate the .asm
// for this file.
C & cr = GetACRef() ; // Note that C is not polymorphic
cr.a.f() ; // visual C++ 2010 generates call to f using virtual dispatching
cr.b.f() ; // visual C++ 2010 generates call to f using virtual dispatching
}
答案 0 :(得分:3)
显然,编译器编写者并没有费心去解决这种情况。也许在实际代码中不值得引起他们的注意。
如果在其他地方定义GetACRef
,那么C也可能是多态的,这可能会影响优化。
请注意,编译器并未解决小型测试程序对人类“显而易见”的所有情况。编译器的重点是经常在大型实际程序中发生的情况。
答案 1 :(得分:2)
我不知道为什么MSVC不会将你的“案例2”场景编译成直接调用 - 这当然是可能的。我认为只有微软才能回答。
请注意,GCC会执行您正在寻找的优化(使用MinGW 4.5.1和-O2
进行测试)。
此外,MSVC甚至按以下顺序使用vtable调度(为清楚起见 - 我正在使用/Ox
优化选项):
A a;
A& ar(a);
ar.f();
因此,不需要函数或容器结构来向编译器添加潜在的混淆层 - 编译器没有理由不能将ar.f()
与该序列中的a.f()
完全相同。但正如Bo Persson所暗示的那样,也许这不是一个非常常见的优化方案(或者MS很明显没有得到它)。同样,只有MS的编译器开发人员才能回答。
我不确定我是否会将此行为归类为“奇怪” - 这是一个错过的优化机会。我不确定这种事情有多常见。在这种情况下,您是否希望编译器生成静态绑定调用?也许。但我认为不会发生这种情况并不太令人惊讶。
也许应该在MS Connect上打开一个问题。