What's the point of a final virtual function?

2019-01-11 08:28发布

Wikipedia has the following example on the C++11 final modifier:

struct Base2 {
    virtual void f() final;
};

struct Derived2 : Base2 {
    void f(); // ill-formed because the virtual function Base2::f has been marked final
};

I don't understand the point of introducing a virtual function and immediately marking it as final. Is this simply a bad example, or is there more to it?

10条回答
女痞
2楼-- · 2019-01-11 09:04

While refactoring legacy code (e.g. removing a method that is virtual from a mother class), this is useful to ensure none of the child classes are using this virtual function.

// Removing foo method is not impacting any child class => this compiles
struct NoImpact { virtual void foo() final {} };
struct OK : NoImpact {};

// Removing foo method is impacting a child class => NOK class does not compile
struct ImpactChildClass { virtual void foo() final {} };
struct NOK : ImpactChildClass { void foo() {} };

int main() {}
查看更多
Explosion°爆炸
3楼-- · 2019-01-11 09:05

Typically final will not be used on the base class' definition of a virtual function. final will be used by a derived class that overrides the function in order to prevent further derived types from further overriding the function. Since the overriding function must be virtual normally it would mean that anyone could override that function in a further derived type. final allows one to specify a function which overrides another but which cannot be overridden itself.

For example if you're designing a class hierarchy and need to override a function, but you do not want to allow users of the class hierarchy to do the same, then your might mark the functions as final in your derived classes.

查看更多
Juvenile、少年°
4楼-- · 2019-01-11 09:05

It doesn't seem useful at all to me. I think this was just an example to demonstrate the syntax.

One possible use is if you don't want f to really be overrideable, but you still want to generate a vtable, but that is still a horrible way to do things.

查看更多
小情绪 Triste *
5楼-- · 2019-01-11 09:07

For a function to be labelled final it must be virtual, i.e., in C++11 §10.3 para. 2:

[...] For convenience we say that any virtual function overrides itself.

and para 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. [...]

i.e., final is required to be used with virtual functions (or with classes to block inheritance) only. Thus, the example requires virtual to be used for it to be valid C++ code.

EDIT: To be totally clear: The "point" asked about concerns why virtual is even used. The bottom-line reason why it is used is (i) because the code would not otherwise compile, and, (ii) why make the example more complicated using more classes when one suffices? Thus exactly one class with a virtual final function is used as an example.

查看更多
我命由我不由天
6楼-- · 2019-01-11 09:15

I don't understand the point of introducing a virtual function and immediately marking it as final.

The purpose of that example is to illustrate how final works, and it does just that.

A practical purpose might be to see how a vtable influences a class' size.

struct Base2 {
    virtual void f() final;
};
struct Base1 {
};

assert(sizeof(Base2) != sizeof(Base1)); //probably

Base2 can simply be used to test platform specifics, and there's no point in overriding f() since it's there just for testing purposes, so it's marked final. Of course, if you're doing this, there's something wrong in the design. I personally wouldn't create a class with a virtual function just to check the size of the vfptr.

查看更多
ゆ 、 Hurt°
7楼-- · 2019-01-11 09:21

virtual + final are used in one function declaration for making the example short.

Regarding the syntax of virtual and final, the Wikipedia example would be more expressive by introducing struct Base2 : Base1 with Base1 containing virtual void f(); and Base2 containing void f() final; (see below).

Standard

Referring to N3690:

  • virtual as function-specifier can be part of decl-specifier-seq
  • final can be part of virt-specifier-seq

There is no rule having to use the keyword virtual and the Identifiers with special meaning final together. Sec 8.4, function definitions (heed opt = optional):

function-definition:

attribute-specifier-seq(opt) decl-specifier-seq(opt) declarator virt-specifier-seq(opt) function-body

Practice

With C++11, you can omit the virtual keyword when using final. This compiles on gcc >4.7.1, on clang >3.0 with C++11, on msvc, ... (see compiler explorer).

struct A
{
    virtual void f() {}
};

struct B : A
{
    void f() final {}
};

int main()
{
    auto b = B();
    b.f();
}

PS: The example on cppreference also does not use virtual together with final in the same declaration.

PPS: The same applies for override.

查看更多
登录 后发表回答