简体   繁体   English

最终课程的用例

[英]Use cases for final classes

I was reading comments on Herb Sutter's Guru of the Week redux about virtual functions, and finally saw him mentioning this: 我读的意见对周终极版关于香草萨特的大师virtual函数,终于看见他提这一点:

[...] “uses of final are rarer” – well, they sort of are. [...]使用final的情况较为罕见–嗯,它们确实是这样。 I don't know of many, and during standardization Bjarne repeatedly asked for examples of problems it solved and patterns where it should be used, and I don't recall any major ones that stood out. 我所知不多,在标准化过程中,Bjarne反复询问了解决问题的示例以及应使用的模式,并且我不记得有什么突出的问题。 The only one I know of offhand is that if you're defining a library module (which isn't a Standard concept yet) then making leaf classes final can give the compiler more information to devirtualize calls because of knowing code outside the library won't further derive, but I'm not sure how important that is these days in the presence of whole program optimization including aggressive devirtualization. 我唯一知道的一件事是,如果您要定义一个库模块(还不是标准概念),那么使叶子类成为final可以为编译器提供更多信息,以使虚拟化调用,因为知道库外的代码不会。可以进一步推论,但是我不确定在包括积极的去虚拟化在内的整个程序优化的情况下,这几天有多重要。

That answer does not provide many examples about the use cases for final on classes, and I would be interested in knowing what problems it can really solve. 该答案没有提供有关final on class的用例的许多示例,我很想知道它可以真正解决什么问题。 Do you know any, or will final on classes only become some obscure and almost unused feature? 您知道吗,或者final上课只会变得有些晦涩,几乎没有使用吗?

One interesting unusual use case I have found I described here . 我发现我在这里描述一个有趣的不寻常用例。 In short, by preventing inheritance from your int-like class, you buy yourself a possibility to replace it with a built-in type in the future releases of your library, without the risk of breaking your user's code. 简而言之,通过防止从类似int的类继承,您可以自己在将来的库发行版中将其替换为内置类型,而不必担心会破坏用户代码。

But a more common example is devirtualization . 但是更常见的例子是虚拟化 If you mark your class as final, compiler can apply certain run-time optimizations. 如果将类标记为final,则编译器可以应用某些运行时优化。 For instance, 例如,

struct Object {
  virtual void run() = 0;
  virtual ~Object() {}
};

struct Impl final : Object
{
  void run() override {}
};

void fun(Impl & i)
{
  i.run(); // inlined!
}

The call to i.run() can be now inlined due to final specifier. 由于final说明符,现在可以内联对i.run()的调用。 The compiler knows that vtable look-up will not be needed. 编译器知道将不需要进行vtable查找。

final might be useful when you provide a (sort of) facade to the initial interface, which is easier to use by subclasses. 当您为初始接口提供(某种)外观时, final可能会有用,子类更易于使用。 Consider: 考虑:

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();
  } 
}       

Now if you want to derive from Stepper you see that you should override MoveRight and MoveLeft , but you shouldn't override GoTo . 现在,如果您想从Stepper派生,您会看到应该覆盖MoveRightMoveLeft ,但是不应该覆盖GoTo

It is obvious on this small example, but if IMovable had 20 methods and Stepper had 25, and there were default implementations, than you might have hard time figuring out what you should and what you shouldn't override. 在这个小例子上很明显,但是如果IMovable有20种方法,而Stepper有25种方法,并且有默认实现,那么您可能很难确定应该覆盖什么和不应该覆盖什么。 I have met a situation like this in a hardware-related library. 我在与硬件相关的库中遇到了这种情况。 But I wouldn't call this a major problem worth adressing by the standard;) 但是我不认为这是值得通过标准解决的主要问题;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM