虚拟决赛和非虚拟决赛有什么区别?

What is the difference between virtual final and non-virtual?

提问人:Peter 提问时间:9/20/2023 最后编辑:Jan SchultkePeter 更新时间:9/20/2023 访问量:125

问:

声明新的(非覆盖)成员函数与仅声明非虚拟函数之间有什么区别?virtual final

我猜编译器无论如何都会将成员函数(不覆盖任何内容)优化为非虚拟函数,但也许我在这里错了。virtual final

C++ 最终 虚拟函数

评论

2赞 Patrick Roberts 9/20/2023
我怀疑差异在于结果类的 ABI。
2赞 Jarod42 9/20/2023
virtual void foo() final使类具有多态性(因此您可以对其使用)。dynamic_cast
1赞 Evg 9/20/2023
一个区别是编译器仍然需要初始化 .vptr
0赞 Caleth 9/20/2023
@Evg谁说有?vptr
1赞 Evg 9/20/2023
@Caleth 我们称之为实际差异。有没有实现虚函数的编译器?vptr

答:

6赞 Yakk - Adam Nevraumont 9/20/2023 #1

拥有虚拟方法意味着您是动态投射的合法目标,并且您不能成为标准布局。

ABI 明智的我怀疑编译器不会做额外的工作来消除方法,因此带有条目的 vtable 仍然存在,除非在“假设”下消除整个类。final

但是在每个调用点,它们都可以绕过 vtable 并直接调用方法(假设编译器在调用站点上知道该方法的地址;某些动态加载设置可能会使调用站点知道 vtable,但方法地址不是)。

这还可以防止派生类重写此确切的签名。结婚

struct Parent {
  void foo();
};
struct Child:Parent {
  void foo();
};

这是合法的,而

struct Parent {
  virtual void foo() final;
};
struct Child:Parent {
  void foo();
};

莫。依靠这一点是脆弱的,因为

struct Parent {
  virtual void foo() final;
};
struct Child:Parent {
  void foo() const;
};

又是合法的。

评论

0赞 Peter 9/20/2023
啊,好的,所以虚拟 final 阻止任何 Child 使用完全相同的签名,但它在运行时方面不会花费任何费用,对吧?
3赞 Yakk - Adam Nevraumont 9/20/2023
@Peter我没有说“在运行时间方面不花任何钱”。我说它可能会改变 ABI 并阻止它成为标准布局,并且 vtable 可能存在。所有这些都会在运行时产生影响。“不花任何钱”是一个非常强烈的需求,因为即使是微不足道的成本也会使它失败。
0赞 Peter 9/20/2023
好吧,对不起,你是对的。但它在运行时的成本可能不像人们怀疑的虚拟方法那么高。谢谢你的解释。
2赞 user17732522 9/20/2023
"ABI 明智的我怀疑编译器不会做额外的工作来消除最终方法“:即使他们这样做了,也不会改变类是多态的,因此 和 在多态类型上的行为仍然需要工作。因此,无论哪种方式,消除 vptr 对我来说似乎都是不可能的。dynamic_casttypeid
0赞 Caleth 9/20/2023
只有当有人确实这样做了或这样的对象时,@user17732522,并且只有当编译器选择不将这些对象放入其他对象时dynamic_casttypeid