【发布时间】:2020-05-12 21:43:16
【问题描述】:
final 是一个很好的关键字。它让我可以防止从一个类继承。它还允许编译器在调用虚函数或访问虚基时跳过运行时调度机制。
现在假设我有一些非final 类T 带有虚函数和/或基类。还假设我有一个对此类的实例的引用。 我如何告诉编译器这个特定的引用是对完全派生的完整对象,而不是对派生更多类型的基本子对象?
我的动机是像 optional 和 vector 这样的课程。如果我调用optional<T>::operator*(),我会得到一个T&。但是,我可以肯定地知道这个引用确实是一个T,而不是一些更派生的对象。这同样适用于vector<T> 以及我访问其元素的所有方式。
我认为在这种情况下跳过动态分派会是一个很好的优化,尤其是在调试模式和不够聪明的编译器上,无法查看 optional 和 vector 实现并去虚拟化调用。
【问题讨论】:
-
像这样的“伟大的优化”通常会带来不那么高的代价,即降低代码的可读性并且在执行时间上没有实际差异。
-
这里只是吹毛求疵,但
final(以及override)并不是真正的关键字。它们是仅在某些上下文中识别的特殊标识符。拥有一个名为final的函数是完全有效的。如果它是一个成员函数,你甚至可以将它标记为final就像void final() final;:) -
你甚至可以设计一个
final final() final;有效的场景。 -
正确的做法是标记你的
T类final。你为什么不这样做?您可以确定T&确实是对编译器强制执行的具体T的引用。当有人将您的T子类化并且您的“确定性”消失时,以任何其他方式进行操作只是在自找麻烦。更不用说编译器在识别引用的具体类型和跳过虚拟调度方面可能比你想象的更聪明...... -
您是在谈论单个翻译单元中的所有代码吗?或者该函数的实现是否在与可选翻译单元不同的翻译单元中引用?
标签: c++ c++11 inheritance polymorphism final