22

我正在阅读Herb Sutter 的 Guru of the Week redux 关于函数的评论virtual,最后看到他提到了这一点:

[...] “final 的使用比较少”——嗯,确实是这样。我不知道有多少,在标准化过程中,Bjarne 反复询问它解决的问题的示例以及应该在哪些地方使用它的模式,我不记得有任何突出的主要问题。我唯一知道的是,如果您要定义一个库模块(这还不是标准概念),那么将叶类设为 final 可以为编译器提供更多信息来去虚拟化调用,因为知道库之外的代码不会' t 进一步推导,但我不确定这些天在包括积极去虚拟化在内的整个程序优化存在的情况下有多重要。

该答案没有提供很多final关于类用例的示例,我很想知道它可以真正解决哪些问题。您知道吗,或者final课程只会成为一些晦涩且几乎未使用的功能?

4

2 回答 2

9

我发现我在这里描述的一个有趣的不寻常用例。简而言之,通过防止从类 int 类继承,您可以在将来的库版本中将其替换为内置类型,而不会有破坏用户代码的风险。

但更常见的例子是去虚拟化。如果将类标记为最终类,编译器可以应用某些运行时优化。例如,

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 查找。

于 2013-12-10T12:24:08.393 回答
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 派生,你会看到你应该覆盖MoveRightand MoveLeft,但你不应该覆盖GoTo

在这个小例子中很明显,但是如果IMovable有 20 个方法,而 Stepper 有 25 个,并且有默认实现,那么您可能很难弄清楚应该覆盖什么和不应该覆盖什么。我在硬件相关的库中遇到过这样的情况。但我不认为这是一个值得按标准解决的主要问题;)

于 2013-12-10T12:48:44.580 回答