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

122,849

Solution 1

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!
};

Solution 2

  • 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

Solution 3

"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().

Solution 4

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

Solution 5

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.)

Share:
122,849

Related videos on Youtube

lezebulon
Author by

lezebulon

Updated on August 07, 2021

Comments

  • lezebulon
    lezebulon almost 3 years

    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?

    • ildjarn
      ildjarn over 12 years
      "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.
    • Steve Holgado
      Steve Holgado over 12 years
      @ildjarn 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..
    • Alex Kremer
      Alex Kremer over 12 years
      @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.
    • Alex Kremer
      Alex Kremer over 12 years
      @ildjarn i think you meant that you don't have to specify 'virtual' keyword in the terminal class.. otherwise you are wrong.
    • ildjarn
      ildjarn over 12 years
      @DanO : If it's not virtual in the super class then it wouldn't be "overriding".
    • abhimanyuaryan
      abhimanyuaryan about 9 years
      @ildjarn 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.
    • ildjarn
      ildjarn about 9 years
      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.
    • Cheshar
      Cheshar about 4 years
      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.
  • lezebulon
    lezebulon over 12 years
    thanks, but I forgot to mention that my question concerned the use of "final" with methods
  • Aaron McDaid
    Aaron McDaid over 12 years
    You did mention it @lezebulon :-) "what is the purpose of the "final" keyword in C++11 for functions". (my emphasis)
  • lezebulon
    lezebulon over 12 years
    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 overriden
  • lezebulon
    lezebulon over 12 years
    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 themselves
  • Steve Holgado
    Steve Holgado over 12 years
    @lezebulon: Your leaf classes do not need to mark a function as virtual if the super class declared it as virtual.
  • Aaron McDaid
    Aaron McDaid over 12 years
    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?
  • Aaron McDaid
    Aaron McDaid over 12 years
    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.
  • ildjarn
    ildjarn over 12 years
    @Aaron : Edits made within five minutes after posting aren't reflected in the revision history.
  • Aaron McDaid
    Aaron McDaid over 12 years
    @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.
  • David Rodríguez - dribeas
    David Rodríguez - dribeas over 12 years
    @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 hides
  • kfsone
    kfsone over 10 years
    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.
  • Andrew Cheong
    Andrew Cheong almost 10 years
    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*...
  • Jitsu
    Jitsu over 9 years
    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.
  • David Rodríguez - dribeas
    David Rodríguez - dribeas over 9 years
    @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.
  • Destructor
    Destructor about 9 years
    @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?
  • Nawaz
    Nawaz about 9 years
    @PravasiMeet: They're contextual keywords. Yes, you're right.
  • Vincent Fourmond
    Vincent Fourmond over 7 years
    Anyone know of a compiler that makes use of those now ?
  • Kaitain
    Kaitain over 6 years
    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.
  • crazii
    crazii over 5 years
    same thing that I want to say.
  • greggo
    greggo over 4 years
    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.
  • Job_September_2020
    Job_September_2020 about 3 years
    @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 ?
  • Nawaz
    Nawaz about 3 years
    @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.
  • Job_September_2020
    Job_September_2020 about 3 years
    @Nawaz, OK. It makes sense in that scenario. Thanks.
  • htmlboss
    htmlboss about 3 years
    @VincentFourmond @crazii 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.
  • Vincent Fourmond
    Vincent Fourmond about 3 years
    @htmlboss Thanks !
  • Ajay
    Ajay almost 3 years
    virtual void myfun() final in base class is apparently meaningless.
  • Ajay
    Ajay almost 3 years
    struct Base2 { virtual void f() final;}; is absurd!
  • cyb70289
    cyb70289 almost 3 years
    This is the most useful answer here. IMO, the high score answers are correct but as boring as cppreference.
  • VMMF
    VMMF over 2 years
    Why not public B { void foo() final; }; ? Why putting virtual in class B if we already put final?