struct base {
virtual int f () const = 0;
};
struct derived : public base {
virtual int f () const final { return 2; }
};
int returnf(const base& b)
{
return b.f();
}
程序集(x86-64 gcc12.2,-标准=c++20 -O3):
main:
xor eax,eax
ret
cs nop WORD PTR [rax+rax*1+0x0]
nop DWORD PTR [rax]
returnf(base const&):
mov rax,QWORD PTR [rdi]
mov rax,QWORD PTR [rax]
cmp rax,0x401140
jne 401138 <returnf(base const&)+0x18>
mov eax,0x2
ret
nop DWORD PTR [rax+0x0]
jmp rax
nop WORD PTR [rax+rax*1+0x0]
derived::f() const:
mov eax,0x2
ret
cs nop WORD PTR [rax+rax*1+0x0]
在这里,您可以在程序集中看到虚函数调用没有完全优化掉,也就是说,仍然要检查对象是否是派生的类型:
cmp rax,0x401140
jne 401138 <returnf(base const&)+0x18>
3条答案
按热度按时间s71maibg1#
存在多态是因为存在虚函数,并且可以从基类定义其他派生类。
从C++ 17标准(13.3虚拟函式)
1 [注意:虚函数支持动态绑定和面向对象的编程。- end note ]声明或继承虚函数的类称为多态类。
nx7onnlm2#
编译器是否会通过避免使用虚拟表来优化代码
如果编译器有一个
pDerived->f()
,那么是的,这是它通常会做的,因为这是final
最初设计的目的。如果它有一个
pBase->f()
,则只有当编译器能够证明pBase
指向derived
而不是从base
派生的任何其它类时,这种优化才是可能的。f
是否被声明为final
与该分析无关。编译器通常一次只能看到一个翻译单元,因此需要进行某种数据流分析来消除这种可能性。链接时优化在这里并没有真正的帮助,因为额外的模块可以在运行时加载,而链接时优化器看不到它们。yqlxgs2m3#
我在编译器资源管理器中做了一个例子:https://godbolt.org/z/exsx8dzra
代码:
程序集(x86-64 gcc12.2,-标准=c++20 -O3):
在这里,您可以在程序集中看到虚函数调用没有完全优化掉,也就是说,仍然要检查对象是否是派生的类型:
如果是,则返回方法中指定的值,否则跳转到rax