C++ final 是否在所有方面都意味着最终?

Does C++ final imply final in all aspects?

C++11 added final.

终于!

我明白 final 做了两件事:

这两者似乎相互独立。但举个例子:

class Foo
{
    public:
    virtual void bar()
    {
        //do something unimportant.
    }
};
class Baz final : public Foo
{
    public:
    void bar() /*final*/ override
    {
        //do something more important than Foo's bar.
    }
};

从上面,我认为 Bazfinal,我 应该 NOT 需要指定 virtual成员函数bar也是final。由于无法继承 Baz,因此覆盖 bar 的问题超出了范围。但是我的编译器 VC++ 2015 对此非常安静。我目前还没有在其他任何人身上测试过。

如果有人能阐明这个话题,我会很高兴。引用标准(如果有的话)将不胜感激。也请说明我不知道的任何极端情况,这可能会导致我的逻辑信念失败。

所以,我的问题是:final class是否隐含地暗示它virtual的功能也是 final ?应该是?请说明。


我问这个的原因是因为 final 函数符合 去虚拟化 的条件,这是一个很好的优化。感谢任何帮助。

The reason I am asking this is because final functions become qualified for de-virtualization, which is a great optimization.

是吗? "De-virtualization" 不是 C++ 标准的一部分。或者至少,不是真的。

去虚拟化只是 "as if" 规则的结果,该规则规定只要实现的行为符合标准,实现就可以做任何它喜欢的事情 "as if"。

如果编译器可以在编译时检测到通过多态类型对虚拟成员函数的特定调用将无可否认地调用该函数的特定版本,则允许避免使用虚拟调度逻辑并静态调用该函数。这是行为 "as if" 它使用了虚拟调度逻辑,因为编译器可以证明这是将被调用的函数。

因此,该标准未定义何时进行去虚拟化 allowed/forbidden。编译器在内联一个函数时,该函数采用指向基 class 类型的指针,可能会发现传递的指针指向函数中声明的局部堆栈变量,它正在内联。或者编译器可以追踪特定 inline/call 图到特定多态 pointer/reference 的原点。在这些情况下,编译器可以去虚拟化对该类型的调用。但前提是它足够聪明才能这样做。

编译器是否会将所有对 final class 的虚函数调用去虚拟化,而不管这些方法是否声明为 final 本身?它可能。它可能不会。它甚至可能不会去虚拟化对多态类型上声明的 final 方法的任何调用。这是一个有效的(如果不是特别聪明的话)实现。

你问的问题是特定于实现的。它可能因编译器而异。

但是,正如您所指出的,class 被声明为 final 应该足以让编译器将对 pointers/references 的所有调用去虚拟化为 final class类型。如果编译器不这样做,那就是实现质量问题,而不是标准问题。

从这里引用 C++ 标准草案 [class.virtual/4]:

If a virtual function f in some class B is marked with the virt-specifier final and in a class D derived from B a function D::f overrides B::f, the program is ill-formed.

这里 [class/3]:

If a class is marked with the class-virt-specifier final and it appears as a base-type-specifier in a base-clause (Clause [class.derived]), the program is ill-formed.

所以,回答问题;

Does a final class implicitly imply its virtual functions to be final as well? Should it? Please clarify.

所以,至少不是正式的。在这两种情况下,任何违反任何一条规则的企图都会产生相同的结果;该程序格式错误,无法编译。 final class 意味着 class 不能派生自,因此,它的 virtual 方法不能被覆盖。

应该吗?至少在形式上,可能不是;它们是相关的,但它们不是一回事。也无须刻意要求一者暗示另一者,效果自然而然。任何违规行为都有相同的结果,即编译失败(希望有适当的错误消息来区分两者)。


谈谈你查询的动机和虚拟调用的去虚拟化。这并不总是立即受到 class 的 final 或方法(尽管它们提供帮助)的影响,虚函数的正常规则和 class 层次结构适用。

如果编译器可以确定在运行时将始终调用特定方法(例如使用自动对象,即“在堆栈上”),它可以应用这样 an optimisation anyway, irrespective of the method being marked final or not. These optimisations fall under the "as-if" rule, that allow the compiler to apply any transformation 只要可观察到的行为就好像原来的代码已经被执行了一样。

Does a final class implicitly imply its virtual functions to be final as well?

[...]

I am asking this is because final functions become qualified for de-virtualization, which is a great optimization.

,为了去虚拟化,在所有主要编译器(包括 MSVC)中确实如此:

struct B                   { virtual void f() = 0;   };

struct D1       : public B {         void f();       };
struct D2       : public B {         void f() final; };
struct D3 final : public B {         void f();       };

void f1(D1& x) { x.f(); } // Not de-virtualized
void f2(D2& x) { x.f(); } //     De-virtualized
void f3(D3& x) { x.f(); } //     De-virtualized