我正在阅读Herb Sutter的本周大师关于virtual
函数的comments,最后看到他提到这个:
[...]“最终的使用是罕见的” - 嗯,他们有点。我不知道很多,在标准化过程中,Bjarne反复询问它解决的问题和应该使用的模式的例子,我不记得任何突出的主要问题。我唯一知道的是,如果你正在定义一个库模块(它还不是标准概念),那么使叶子类最终可以为编译器提供更多信息来虚拟化调用,因为知道库外的代码“进一步推导出来,但我不确定这些日子在整个项目优化过程中有多重要,包括积极的虚拟化。
这个答案没有提供关于类final
的用例的很多例子,我很想知道它可以解决哪些问题。你知道吗,或者final
课程只会变成一些模糊不清且几乎未使用的功能?
答案 0 :(得分:9)
我发现一个有趣的不寻常的用例我描述了here。简而言之,通过阻止类似int类的继承,您可以在库的未来版本中使用内置类型替换它,而不会有破坏用户代码的风险。
但更常见的例子是 devirtualization 。如果将类标记为final,则编译器可以应用某些运行时优化。例如,
struct Object {
virtual void run() = 0;
virtual ~Object() {}
};
struct Impl final : Object
{
void run() override {}
};
void fun(Impl & i)
{
i.run(); // inlined!
}
由于i.run()
说明符,现在可以内联对final
的调用。编译器知道不需要vtable查找。
答案 1 :(得分:0)
final
可能很有用,后者更容易被子类使用。
考虑:
class IMovable {
public:
void GoTo(unsigned position) = 0;
}
class Stepper : public IMovable {
public:
void GoTo(unsigned position) final;
protected:
virtual void MoveLeft() = 0;
virtual void MoveRight() = 0;
}
void Stepper::GoTo(unsigned position) {
for(;current_pos < position; current_pos++) {
MoveRight();
}
for(;current_pos > position; current_pos--) {
MoveLeft();
}
}
现在,如果您想从Stepper派生,您会看到应该覆盖MoveRight
和MoveLeft
,但不应覆盖GoTo
。
这个小例子很明显,但是如果IMovable
有20个方法而Stepper有25个,并且有默认实现,那么你可能很难搞清楚你应该做什么以及你不应该覆盖什么。我在硬件相关的库中遇到过这样的情况。但我不认为这是一个值得通过标准来解决的主要问题;)