74

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?

iBug
  • 35,554
  • 7
  • 89
  • 134
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • 3
    Well, Java has it, so you know, C++'s gotta have it too. – chris Jul 28 '12 at 20:28
  • 13
    I guess that's just a bad example – Man of One Way Jul 28 '12 at 20:28
  • I would agree. It would make sense to edit the wikipedia article. – Kirill Kobelev Jul 28 '12 at 20:31
  • 3
    Fun fact: (Nearly) the same example can be found in the standard under §10.3/4. – Xeo Jul 28 '12 at 20:32
  • 3
    You can always use it to confuse people by using the keyword as an identifier: `int final = 7;` If you want Stroustrup's talk on it, though, [see here](http://stroustrup.com/C++11FAQ.html#final). – chris Jul 28 '12 at 20:33
  • It is needed for the code to be valid C++ code. If you remove virtual from your code, then it is not a valid C++ program. (See my answer below.) – Paul Preney Jul 28 '12 at 21:09
  • @Kirill Kobelev: They should reject your edit request as it would not be valid C++ code. – Paul Preney Jul 28 '12 at 21:10
  • @PaulPreney, how can you decide that edit will be rejected without seeing it first? – Kirill Kobelev Jul 28 '12 at 21:12
  • 3
    What part of "It's an example" is difficult to understand? Most of the other pieces of example code are similarly pointless. The purpose of an example is to show how the functionality works. – Nicol Bolas Jul 28 '12 at 21:34
  • @Kirill Kobelev: Clearly nobody can decide without seeing it, but, if it merely removed virtual, then it wouldn't be valid C++ code any more. Your comment to edit the Wikipedia entry seemed to imply such. – Paul Preney Jul 29 '12 at 01:53

11 Answers11

79

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 you might mark the functions as final in your derived classes.


Since it's been brought up twice in the comments I want to add:

One reason some give for a base class to declare a non-overriding method to be final is simply so that anyone trying to define that method in a derived class gets an error instead of silently creating a method that 'hides' the base class's method.

struct Base {
   void test() { std::cout << "Base::test()\n"; }
};

void run(Base *o) {
    o->test();
}


// Some other developer derives a class
struct Derived : Base {
   void test() { std::cout << "Derived::test()\n"; }
};

int main() {
    Derived o;
    o.test();
    run(&o);
}

Base's developer doesn't want Derived's developer to do this, and would like it to produce an error. So they write:

struct Base {
    virtual void test() final { ... }
};

Using this declaration of Base::foo() causes the definition of Derived to produce an error like:

<source>:14:13: error: declaration of 'test' overrides a 'final' function
       void test() { std::cout << "Derived::test()\n"; }
            ^
<source>:4:22: note: overridden virtual function is here
        virtual void test() final { std::cout << "Base::test()\n"; }
                     ^

You can decide if this purpose is worthwhile for yourself, but I want to point out that declaring the function virtual final is not a full solution for preventing this kind of hiding. A derived class can still hide Base::test() without provoking the desired compiler error:

struct Derived : Base {
   void test(int = 0) { std::cout << "Derived::test()\n"; }
};

Whether Base::test() is virtual final or not, this definition of Derived is valid and the code Derived o; o.test(); run(&o); behaves exactly the same.

As for clear statements to users, personally I think just not marking a method virtual makes a clearer statement to users that the method is not intended to be overridden than marking it virtual final. But I suppose which way is clearer depends on the developer reading the code and what conventions they are familiar with.

bames53
  • 86,085
  • 15
  • 179
  • 244
  • 2
    Wouldn't it make sense then if `final` implicitly meant `override final`? – fredoverflow Jul 28 '12 at 21:50
  • 5
    I don't see any reason why not, but I also don't see any strong reason to do it since you can already mark functions `final override`. Perhaps there should be a style warning that requires all `final` functions to also be marked `override` like the other `virtual` and `override` style warnings. – bames53 Jul 29 '12 at 01:29
  • Well final methods in interfaces would be an example of a final method in a "base" class. Also 'final' yields an error or at least a warning if somebody defines a function with the same name in a subclass. The question is if compilers immediately devirtualize such a case. – Trass3r Mar 11 '13 at 13:58
  • 2
    @Trass3r It would not be possible to implement a `final` interface method, because implementing an interface method in C++ requires overriding. Such an unimplementable interface would not be useful. – bames53 Mar 11 '13 at 21:19
  • Yes, that's why you implement it in the interface. – Trass3r Mar 12 '13 at 08:29
  • @Trass3r Ah, I see what you're saying. However I don't think this works very well; it doesn't prevent hiding because you can still declare functions of the same name but different signatures in derived classes (and such functions can use default arguments to have effectively the same signature, and there's usually a warning about hiding anyway) and secondly you can only override virtual functions so just not marking the base function virtual would prevent overriding. Finally, using `virtual` this way seems like obfuscation to me. – bames53 Mar 12 '13 at 16:02
  • @bames53: I doubted your comment about functions using default arguments to have effectively the same signature, [but you're right](http://ideone.com/TnCbVE). Also, virtual is required to use final. – idbrii Jul 07 '14 at 22:00
  • `virtual final` for a base class method has a use case https://stackoverflow.com/a/44153376/2436175 – Antonio May 02 '22 at 08:25
  • @Antonio It doesn't actually prevent hiding. E.g. I can still do [this](http://coliru.stacked-crooked.com/a/d0e4767a8009be4b). Using `virtual final` for this purpose seems janky and I don't think I'd recommend trying it. – bames53 May 03 '22 at 15:11
  • @bames53 The thing is open to debate (there's some consensus on the answer I linked previously), the example you make with the default parameter is a bit extreme, plausible but we can safely say `virtual final` will cover 90% of the errors. Furthermore, by marking as `virtual final` a function in the base class we make a clear statement for the developer deriving that class. A bad developer then can always break things. :) I personally use `virtual final` when I have a base class where most of the members are pure virtual, and I want to warn the developer not to override one specific method. – Antonio May 05 '22 at 08:45
12

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.

Paul Preney
  • 1,283
  • 11
  • 10
  • Respectfully, I totally get the point of the question. The "point" asked about concerns why virtual is even used. The bottom-line reason why it is used is because the code would not otherwise compile AND why make the example more complicated using more classes when one suffices? Thus exactly one class with a virtual final function is used to as an example. QED. – Paul Preney Jul 29 '12 at 02:00
  • @Luchian Grigore: I added an edit to be completely clear since I did not wrap up my answer with the "bottom-line reason". Perhaps why this question is getting so many comments is due to everyone naturally looking at the example and saying, "Why would anyone use that code?" and not looking at it from the example writer's point-of-view. Most examples are written to be practically useful --this one is not except to make a minimal example showing how it behaves. – Paul Preney Jul 29 '12 at 02:30
11

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.

Antimony
  • 37,781
  • 10
  • 100
  • 107
  • Final and virtual are two different aspects. It becomes relevant in the override versus overload context. A virtual qualifier implies Run Time Type Inference. A non-virtual implies compile type type inference. When there is overloading involved, and type promotion/conversion involved a non-virtual type can lead to interesting results. Typically though you are encouraged not to write that kind of code. – VSOverFlow Jul 29 '12 at 23:55
  • Why would you want to generate a vtable if compiler doesn't? – sasha.sochka Aug 12 '13 at 18:23
  • 5
    @sasha.sochka I think for example that `dynamic_cast` won't work without one. But the usual way to ensure a vtable is to make the destructor virtual. – Mark Ransom May 05 '14 at 01:32
8

Adding to the nice answers above - Here is a well-known application of final (very much inspired from Java). Assume we define a function wait() in a Base class, and we want only one implementation of wait() in all its descendants. In this case, we can declare wait() as final.

For example:

class Base { 
   public: 
       virtual void wait() final { cout << "I m inside Base::wait()" << endl; }
       void wait_non_final() { cout << "I m inside Base::wait_non_final()" << endl; }
}; 

and here is the definition of the derived class:

class Derived : public Base {
      public: 
        // assume programmer had no idea there is a function Base::wait() 

        // error: wait is final
        void wait() { cout << "I am inside Derived::wait() \n"; } 
        // that's ok    
        void wait_non_final() { cout << "I am inside Derived::wait_non_final(); }

} 

It would be useless (and not correct) if wait() was a pure virtual function. In this case: the compiler will ask you to define wait() inside the derived class. If you do so, it will give you an error because wait() is final.

Why should a final function be virtual? (which is also confusing) Because (imo) 1) the concept of final is very close to the concept of virtual functions [virtual functions has many implementations - final functions has only one implementation], 2) it is easy to implement the final effect using vtables.

AJed
  • 578
  • 6
  • 11
  • This answer actually explains everything instead of simply stating that "otherwise it would be wrong" or "because it is an example", imho this should be accepted as the answer to this question. – Troyseph Feb 18 '15 at 09:44
6

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.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
6

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() {}
Richard Dally
  • 1,432
  • 2
  • 21
  • 38
2

Here is why you might actually choose to declare a function both virtual and final in a base class:

class A {
    void f();
};

class B : public A {
    void f(); // Compiles fine!
};

class C {
    virtual void f() final;
};

class D : public C {
    void f(); // Generates error.
};

A function marked final has to be also be virtual. Marking a function final prevents you from declaring a function with the same name and signature in a derived class.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • `final` is like `override`, a `final` function doesn't have to be marked `virtual`, in fact, you should only specify one, [according to ISOCPP](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-override) – bobobobo Jun 21 '23 at 06:46
  • @bobobobo - Will that work even if the function was never marked `virtual` in a parent class? – Omnifarious Aug 21 '23 at 05:46
1

Instead of this:

public:
    virtual void f();

I find it useful to write this:

public:
    virtual void f() final
        {
        do_f(); // breakpoint here
        }
protected:
    virtual void do_f();

The main reason being that you now have a single place to breakpoint before dispatching into any of potentially many overridden implementations. Sadly (IMHO), saying "final" also requires that you say "virtual."

Kevin Hopps
  • 707
  • 3
  • 10
0

I found another case where for virtual function is useful to be declared as final. This case is part of SonarQube list of warnings. The warning description says:

Calling an overridable member function from a constructor or destructor could result in unexpected behavior when instantiating a subclass which overrides the member function.

For example:
- By contract, the subclass class constructor starts by calling the parent class constructor.
- The parent class constructor calls the parent member function and not the one overridden in the child class, which is confusing for child class' developer.
- It can produce an undefined behavior if the member function is pure virtual in the parent class.

Noncompliant Code Example

class Parent {
  public:
    Parent() {
      method1();
      method2(); // Noncompliant; confusing because Parent::method2() will always been called even if the method is overridden
    }
    virtual ~Parent() {
      method3(); // Noncompliant; undefined behavior (ex: throws a "pure virtual method called" exception)
    }
  protected:
    void         method1() { /*...*/ }
    virtual void method2() { /*...*/ }
    virtual void method3() = 0; // pure virtual
};

class Child : public Parent {
  public:
    Child() { // leads to a call to Parent::method2(), not Child::method2()
    }
    virtual ~Child() {
      method3(); // Noncompliant; Child::method3() will always be called even if a child class overrides method3
    }
  protected:
    void method2() override { /*...*/ }
    void method3() override { /*...*/ }
};

Compliant Solution

class Parent {
  public:
    Parent() {
      method1();
      Parent::method2(); // acceptable but poor design
    }
    virtual ~Parent() {
      // call to pure virtual function removed
    }
  protected:
    void         method1() { /*...*/ }
    virtual void method2() { /*...*/ }
    virtual void method3() = 0;
};

class Child : public Parent {
  public:
    Child() {
    }
    virtual ~Child() {
      method3(); // method3() is now final so this is okay
    }
  protected:
    void method2() override { /*...*/ }
    void method3() final    { /*...*/ } // this virtual function is "final"
};
dismine
  • 575
  • 13
  • 17
0

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.

Roi Danton
  • 7,933
  • 6
  • 68
  • 80
0

I think most of the answers miss an important point. final means no more override after it has been specified. Marking it on a base class is close to pointless indeed.

When a derived class might get derived further, it can use final to lock the implementation of a given method to the one it provided.

#include <iostream>

class A {
    public:
    virtual void foo() = 0;
    virtual void bar() = 0;
};

class B : public A {
    public:
    void foo() final override { std::cout<<"B::foo()"<<std::endl; }
    void bar() override { std::cout<<"B::bar()"<<std::endl; }
};

class C : public B {
    public:
    // can't do this as B marked ::foo final!
    // void foo() override { std::cout<<"C::foo()"<<std::endl; }
    void bar() override { std::cout<<"C::bar()"<<std::endl; }
};
p m
  • 49
  • 5