我在考虑虚拟通话以及它们的工作原理。据我所知,虚拟调用可以在编译时内联并硬编码为值类型。如果指针类型是一个声明为final的类(比如用c#密封),这可以让编译器做同样的事情吗?
这在目前的编译器中是否完成了很多,还是只是理论上的/太小而无法担心?
答案 0 :(得分:4)
是的,如果声明虚拟函数或类final
,则可以对调用进行虚拟化。例如,给定
struct B {
virtual void f() = 0;
};
struct D1 : B {
virtual void f();
};
struct D2 : B {
virtual void f() final;
};
struct D3 final : D1 {};
void f1(D1 * d) { d->f(); }
void f2(D2 * d) { d->f(); }
void f3(D3 * d) { d->f(); }
在-O1
或更高generates此大会上发出声响:
f1(D1*): # @f1(D1*)
movq (%rdi), %rax
jmpq *(%rax) # TAILCALL
f2(D2*): # @f2(D2*)
jmp D2::f() # TAILCALL
f3(D3*): # @f3(D3*)
jmp D1::f() # TAILCALL
请注意,f1
通过vtable进行了调用,而f2
和f3
中的来电是非虚拟化的。
答案 1 :(得分:2)
我在考虑虚拟通话以及它们的工作原理。据我所知,虚拟调用可以在编译时内联并硬编码为值类型。如果指针类型是一个声明为final的类(比如用c#密封),这可以让编译器做同样的事情吗?
是的,在gcc
调用最终成员并通过最终课程将被虚拟化,并here's the code执行此操作。