What is the purpose of the "final" keyword in C++11 for functions?
Asked Answered
P

12

205

What is the purpose of the final keyword in C++11 for functions? I understand it prevents function overriding by derived classes, but if this is the case, then isn't it enough to declare as non-virtual your final functions? Is there another thing I'm missing here?

Plast answered 11/1, 2012 at 18:25 Comment(9)
"isn't it enough to declare as non-virtual your "final" functions" No, overriding functions are implicitly virtual whether you use the virtual keyword or not.Frail
@Frail that's not true if they weren't declared as virtual in the super class, you can't derive from a class and transform a non-virtual method into a virtual one..Chalaza
@DanO i think you can't override but you can "hide" a method that way.. which leads to many problems as people don't mean to hide methods.Antimissile
@Frail i think you meant that you don't have to specify 'virtual' keyword in the terminal class.. otherwise you are wrong.Antimissile
@DanO : If it's not virtual in the super class then it wouldn't be "overriding".Frail
@Frail deleted the old one. final usage, prevents function overriding by derived classes. Suppose, I have function void func(int); in base class. If final prevents from overriding so the derived class can use different arguments list for func? eg. void func(int, int) final; in the derived class? But this doesn't work. Compiler shows an error that you can't change arguments list.Import
Again, "overriding" has a specific meaning here, which is to give polymorphic behavior to a virtual function. In your example func is not virtual, so there is nothing to override and thus nothing to mark as override or final.Frail
To be pedantic, "final" is not a "keyword" in C++11. It is actually an "identifier" with a special meaning when appearing in a certain context. auto final = 10; std::cout << final; is perfectly valid albeit, horribly written code.Luht
It has to do with the pointer. If you have a base class pointer and it is not marked virtual, it will always use the base class implementation. If you have a derived class pointer, it will use the derived class method, in all circumstances. The point of marking a function virtual is so that pointers to the base class can have their calls forwarded to the derived class implementations. Without marking the function virtual, you will invoke completely different methods depending on whether you are holding the derived class, or if it has been cast to the base.Faltboat
K
172

What you are missing, as idljarn already mentioned in a comment is that if you are overriding a function from a base class, then you cannot possibly mark it as non-virtual:

struct base {
   virtual void f();
};
struct derived : base {
   void f() final;       // virtual as it overrides base::f
};
struct mostderived : derived {
   //void f();           // error: cannot override!
};
Katz answered 11/1, 2012 at 18:36 Comment(7)
Thanks! this is the point I was missing : ie that even your "leaf" classes need to mark their function as virtual even if they intend to override functions, and not to be overridden themselvesPlast
@lezebulon: Your leaf classes do not need to mark a function as virtual if the super class declared it as virtual.Chalaza
The methods in the leaf classes are implicitly virtual if they are virtual in the base class. I think that compilers should warn if this implicit 'virtual' is missing.Torray
@AaronMcDaid: Compilers usually warn about code that, being correct, might cause confusion or errors. I have never seen anyone surprised by this particular feature of the language in a way that could cause any problem, so I don't really know how usefull that error might be. On the contrary, forgetting the virtual can cause errors, and C++11 added the override tag to a function that will detect that situation and fail to compile when a function that is meant to override actually hidesFluker
From GCC 4.9 change notes: "New type inheritance analysis module improving devirtualization. Devirtualization now takes into account anonymous name-spaces and the C++11 final keyword" - so it's not just syntactic sugar, it also has a potential optimization benefit.Artilleryman
What this does is called a "virtualization ceiling" and in the end, except for the syntactical and design profits, you'll get some (maybe relatively small, but still) performance enhancements, as it removes some virtualization from your derived data structures... or at least this will be true on most modern compilers.Nordrheinwestfalen
@Jitsu: The compiler can devirtualize the call if the static type of the object has that member function as final, but if in the code above the static type of the object is base* then the compiler lacks the required information. Still at runtime there are things that would be done to devirtualize, but not anything that would not be doable without final. The use case where the static type is the type of the final overrider, well, I am not too sure that will be the common case.Fluker
Y
166
  • It is to prevent a class from being inherited. From Wikipedia:

    C++11 also adds the ability to prevent inheriting from classes or simply preventing overriding methods in derived classes. This is done with the special identifier final. For example:

    struct Base1 final { };
    
    struct Derived1 : Base1 { }; // ill-formed because the class Base1 
                                 // has been marked final
    
  • It is also used to mark a virtual function so as to prevent it from being overridden in the derived classes:

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

Wikipedia further makes an interesting point:

Note that neither override nor final are language keywords. They are technically identifiers; they only gain special meaning when used in those specific contexts. In any other location, they can be valid identifiers.

That means, the following is allowed:

int const final = 0;     // ok
int const override = 1;  // ok
Yurikoyursa answered 11/1, 2012 at 18:28 Comment(13)
thanks, but I forgot to mention that my question concerned the use of "final" with methodsPlast
You did mention it @Plast :-) "what is the purpose of the "final" keyword in C++11 for functions". (my emphasis)Torray
You edited it? I don't see any message that says "edited x minutes ago by lezebulon". How did that happen? Maybe you edited it very quickly after submitting it?Torray
@Aaron : Edits made within five minutes after posting aren't reflected in the revision history.Frail
@Nawaz: why they aren't keywords just specifiers? Is it due to compatibility reasons means it is possible that preexisting code before C++11 uses final & override for other purposes?Stearns
@PravasiMeet: They're contextual keywords. Yes, you're right.Yurikoyursa
I've seen C code broken when moved to c++, because of 'this' becoming a keyword, and also code broken by 'and' and 'or' becoming reserved words. In fact, you normally only need something to be a keyword if the parser needs to treat it differently from normal identifiers; 'this' could have been implemented as a special identifier which only exists in the namespace of class methods, since it's syntactically the same as a variable name.Interrupter
@Nawaz, I have 1 question about your code "virtual void f() final". I know you said that "final" means that the virtual method cant' be override. But, then what is the point of having both "virtual and final" in that method f() ? In that case, would it be simpler just to remove both "virtual and final" from the method f() and still achieve the same goal ?Touchy
@Job_September_2020: No, they're different things. virtual void f() final means that it cannot be overridden further. The word further is important, which means depending on final status, you can and cannot override a virtual function in a class hierarchy like: A -> B -> C -> D -> E where A declares f() to be a virtual function, B` and C both override it, as per their need but they do not make it final, so D can still override it, but it makes it final, so E CANNOT override it, though it can override other virtual functions (if any). Hope that helps.Yurikoyursa
@Nawaz, OK. It makes sense in that scenario. Thanks.Touchy
struct Base2 { virtual void f() final;}; is absurd!Ruder
Note that you can also use it as class FinalChild final : public Base to avoid FinalChild to be extended further.Shagbark
Upvote for being very detailed.Balaton
S
79

"final" also allows a compiler optimization to bypass the indirect call:

class IAbstract
{
public:
  virtual void DoSomething() = 0;
};

class CDerived : public IAbstract
{
  void DoSomething() final { m_x = 1 ; }

  void Blah( void ) { DoSomething(); }

};

with "final", the compiler can call CDerived::DoSomething() directly from within Blah(), or even inline. Without it, it has to generate an indirect call inside of Blah() because Blah() could be called inside a derived class which has overridden DoSomething().

Selfrenunciation answered 11/7, 2013 at 22:43 Comment(2)
This is the most useful answer here. IMO, the high score answers are correct but as boring as cppreference.Labret
Yes, this also allows pimpl idiom to be free in many situations.Rese
B
44

Nothing to add to the semantic aspects of "final".

But I'd like to add to chris green's comment that "final" might become a very important compiler optimization technique in the not so distant future. Not only in the simple case he mentioned, but also for more complex real-world class hierarchies which can be "closed" by "final", thus allowing compilers to generate more efficient dispatching code than with the usual vtable approach.

One key disadvantage of vtables is that for any such virtual object (assuming 64-bits on a typical Intel CPU) the pointer alone eats up 25% (8 of 64 bytes) of a cache line. In the kind of applications I enjoy to write, this hurts very badly. (And from my experience it is the #1 argument against C++ from a purist performance point of view, i.e. by C programmers.)

In applications which require extreme performance, which is not so unusual for C++, this might indeed become awesome, not requiring to workaround this problem manually in C style or weird Template juggling.

This technique is known as Devirtualization. A term worth remembering. :-)

There is a great recent speech by Andrei Alexandrescu which pretty well explains how you can workaround such situations today and how "final" might be part of solving similar cases "automatically" in the future (discussed with listeners):

http://channel9.msdn.com/Events/GoingNative/2013/Writing-Quick-Code-in-Cpp-Quickly

Birddog answered 22/10, 2013 at 16:58 Comment(6)
Anyone know of a compiler that makes use of those now ?Ceiling
same thing that I want to say.Gsuit
@VincentFourmond @Gsuit I've found another answer on SO which confirms that yes GCC, MSVC, and Clang use final for de-virtualization optimizations. Check the comments for specific compiler versions that added this feature, and even links to the compiler code.Phlebotomize
8 of 64 is 12.5%Vidovik
Link to Writing-Quick-Code-in-Cpp-QuicklyChlorate
Writing-Quick-Code-in-Cpp-Quickly in youtube (more convenient) youtube.com/watch?v=ea5DiCg8HOYChlorate
T
16

Final cannot be applied to non-virtual functions.

error: only virtual member functions can be marked 'final'

It wouldn't be very meaningful to be able to mark a non-virtual method as 'final'. Given

struct A { void foo(); };
struct B : public A { void foo(); };
A * a = new B;
a -> foo(); // this will call A :: foo anyway, regardless of whether there is a B::foo

a->foo() will always call A::foo.

But, if A::foo was virtual, then B::foo would override it. This might be undesirable, and hence it would make sense to make the virtual function final.

The question is though, why allow final on virtual functions. If you have a deep hierarchy:

struct A            { virtual void foo(); };
struct B : public A { virtual void foo(); };
struct C : public B { virtual void foo() final; };
struct D : public C { /* cannot override foo */ };

Then the final puts a 'floor' on how much overriding can be done. Other classes can extend A and B and override their foo, but it a class extends C then it is not allowed.

So it probably doesn't make sense to make the 'top-level' foo final, but it might make sense lower down.

(I think though, there is room to extend the words final and override to non-virtual members. They would have a different meaning though.)

Torray answered 11/1, 2012 at 18:35 Comment(4)
thanks for the example, it's something I was unsure about. But still : what is the point to have a final (and virtual) function? Basically you would never be able to use the fact that the function is virtual since it can't be overridenPlast
@lezebulon, I edited my question. But then I noticed DanO's answer - it's a good clear answer of what I was trying to say.Torray
I'm not an expert, but I feel that sometimes it may make sense to make a top-level function final. For example, if you know you want all Shapes to foo()—something predefined and definite that no derived shape should modify. Or, am I wrong and there's a better pattern to employ for that case? EDIT: Oh, maybe because in that case, one should simply not make the top-level foo() virtual to begin with? But still, it can be hidden, even if called correctly (polymorphically) via Shape*...Mic
Why not public B { void foo() final; }; ? Why putting virtual in class B if we already put final?Blackpool
S
12

A use-case for the 'final' keyword that I am fond of is as follows:

// This pure abstract interface creates a way
// for unit test suites to stub-out Foo objects
class FooInterface
{
public:
   virtual void DoSomething() = 0;
private:
   virtual void DoSomethingImpl() = 0;
};

// Implement Non-Virtual Interface Pattern in FooBase using final
// (Alternatively implement the Template Pattern in FooBase using final)
class FooBase : public FooInterface
{
public:
    virtual void DoSomething() final { DoFirst(); DoSomethingImpl(); DoLast(); }
private:
    virtual void DoSomethingImpl() { /* left for derived classes to customize */ }
    void DoFirst(); // no derived customization allowed here
    void DoLast(); // no derived customization allowed here either
};

// Feel secure knowing that unit test suites can stub you out at the FooInterface level
// if necessary
// Feel doubly secure knowing that your children cannot violate your Template Pattern
// When DoSomething is called from a FooBase * you know without a doubt that
// DoFirst will execute before DoSomethingImpl, and DoLast will execute after.
class FooDerived : public FooBase
{
private:
    virtual void DoSomethingImpl() {/* customize DoSomething at this location */}
};
Sibilate answered 12/9, 2013 at 21:25 Comment(1)
Yes, this is essentially an example of the Template Method Pattern. And pre-C++11, it was always the TMP that had me wishing that C++ had a language feature such as “final”, as Java did.Conger
S
7

final adds an explicit intent to not have your function overridden, and will cause a compiler error should this be violated:

struct A {
    virtual int foo(); // #1
};
struct B : A {
    int foo();
};

As the code stands, it compiles, and B::foo overrides A::foo. B::foo is also virtual, by the way. However, if we change #1 to virtual int foo() final, then this is a compiler error, and we are not allowed to override A::foo any further in derived classes.

Note that this does not allow us to "reopen" a new hierarchy, i.e. there's no way to make B::foo a new, unrelated function that can be independently at the head of a new virtual hierarchy. Once a function is final, it can never be declared again in any derived class.

Sandra answered 11/1, 2012 at 18:32 Comment(0)
C
6

The final keyword allows you to declare a virtual method, override it N times, and then mandate that 'this can no longer be overridden'. It would be useful in restricting use of your derived class, so that you can say "I know my super class lets you override this, but if you want to derive from me, you can't!".

struct Foo
{
   virtual void DoStuff();
}

struct Bar : public Foo
{
   void DoStuff() final;
}

struct Babar : public Bar
{
   void DoStuff(); // error!
}

As other posters pointed out, it cannot be applied to non-virtual functions.

One purpose of the final keyword is to prevent accidental overriding of a method. In my example, DoStuff() may have been a helper function that the derived class simply needs to rename to get correct behavior. Without final, the error would not be discovered until testing.

Chalaza answered 11/1, 2012 at 18:37 Comment(0)
F
4

Final keyword in C++ when added to a function, prevents it from being overridden by derived classes. Also when added to a class prevents inheritance of any type. Consider the following example which shows use of final specifier. This program fails in compilation.

#include <iostream>
using namespace std;

class Base
{
  public:
  virtual void myfun() final
  {
    cout << "myfun() in Base";
  }
};
class Derived : public Base
{
  void myfun()
  {
    cout << "myfun() in Derived\n";
  }
};

int main()
{
  Derived d;
  Base &b = d;
  b.myfun();
  return 0;
}

Also:

#include <iostream>
class Base final
{
};

class Derived : public Base
{
};

int main()
{
  Derived d;
  return 0;
}
Friday answered 29/8, 2016 at 16:38 Comment(1)
virtual void myfun() final in base class is apparently meaningless.Ruder
A
1

Final keyword have the following purposes in C++

  1. If you make a virtual method in base class as final, it cannot be overridden in the derived class. It will show a compilation error:
class Base {
public:
    virtual void display() final  {
        cout << "from base" << endl;
    }
};
class Child : public Base {
public:
    void display() {
        cout << "from child" << endl;
    }
};
int main() {
    Base *b = new Child();
    b->display();
    cin.get();
    return 0;
}

  1. If we make a class as final, it cannot be inherited by its child classes:
class Base final {
public:
    void displayBase()   {
        cout << "from base" << endl;
    }
};
class Child :public Base {
public:
    void displayChild() {
        cout << "from child" << endl;
    }
};

Note: the main difference with final keyword in Java is , a) final is not actually a keyword in C++. you can have a variable named as final in C++ b) In Java, final keyword is always added before the class keyword.

Allemande answered 24/6, 2021 at 7:58 Comment(0)
G
0

Supplement to Mario Knezović 's answer:

class IA
{
public:
  virtual int getNum() const = 0;
};

class BaseA : public IA
{
public:
 inline virtual int getNum() const final {return ...};
};

class ImplA : public BaseA {...};

IA* pa = ...;
...
ImplA* impla = static_cast<ImplA*>(pa);

//the following line should cause compiler to use the inlined function BaseA::getNum(), 
//instead of dynamic binding (via vtable or something).
//any class/subclass of BaseA will benefit from it

int n = impla->getNum();

The above code shows the theory, but not actually tested on real compilers. Much appreciated if anyone paste a disassembled output.

Gsuit answered 28/11, 2018 at 5:59 Comment(0)
R
0

There is also a non-trivial example, related to calling virtual functions from CTORs:

class Base
{
    virtual void func() = 0;
public:
    virtual ~Base() {}
};

class Derived : public Base
{
    void func() override {}
public:
    Derived() { func(); }
};

This calls a virtual function from a CTOR, which is well defined but often seen dangerous. If you now inherit from Derived, a further overridden func will not be called in the Derived CTOR.

In QtCreator, I got this clang-analyzer warning:

virt.cpp:12:17: Call to virtual method 'Derived::func' during construction bypasses virtual dispatch [clang-analyzer-optin.cplusplus.VirtualCall]

However, the warning makes only sense if I ever intend to inherit from Derived. Since I did not, rewriting Derived as class Derived final (or, since the OP asks for it, adding final to the function declaration) silenced this warning for me.

Rabble answered 6/11, 2023 at 23:9 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.