What is the purpose of the "final" keyword in C++11 for functions?
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
norfinal
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.)
Related videos on Youtube
![lezebulon](https://i.stack.imgur.com/1rKE0.jpg?s=256&g=1)
lezebulon
Updated on August 07, 2021Comments
-
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 yourfinal
functions? Is there another thing I'm missing here?-
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 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 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 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 over 12 years@DanO : If it's not virtual in the super class then it wouldn't be "overriding".
-
abhimanyuaryan about 9 years@ildjarn deleted the old one.
final
usage, prevents function overriding by derived classes. Suppose, I have functionvoid func(int);
in base class. Iffinal
prevents from overriding so the derived class can use different arguments list forfunc
? 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 about 9 yearsAgain, "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 asoverride
orfinal
. -
Cheshar about 4 yearsTo 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 over 12 yearsthanks, but I forgot to mention that my question concerned the use of "final" with methods
-
Aaron McDaid over 12 yearsYou did mention it @lezebulon :-) "what is the purpose of the "final" keyword in C++11 for functions". (my emphasis)
-
lezebulon over 12 yearsthanks 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 over 12 yearsThanks! 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 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 over 12 yearsYou 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 over 12 yearsThe 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 over 12 years@Aaron : Edits made within five minutes after posting aren't reflected in the revision history.
-
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 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 theoverride
tag to a function that will detect that situation and fail to compile when a function that is meant to override actually hides -
kfsone over 10 yearsFrom 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 almost 10 yearsI'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 allShape
s tofoo()
—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-levelfoo()
virtual
to begin with? But still, it can be hidden, even if called correctly (polymorphically) viaShape*
... -
Jitsu over 9 yearsWhat 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 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 isbase*
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 withoutfinal
. 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 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 about 9 years@PravasiMeet: They're contextual keywords. Yes, you're right.
-
Vincent Fourmond over 7 yearsAnyone know of a compiler that makes use of those now ?
-
Kaitain over 6 yearsYes, 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 over 5 yearssame thing that I want to say.
-
greggo over 4 yearsI'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 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 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 onfinal
status, you can and cannot override a virtual function in a class hierarchy like:A -> B -> C -> D -> E
whereA
declaresf()
to be avirtual function,
B` andC
both override it, as per their need but they do not make itfinal
, soD
can still override it, but it makes itfinal
, soE
CANNOT override it, though it can override other virtual functions (if any). Hope that helps. -
Job_September_2020 about 3 years@Nawaz, OK. It makes sense in that scenario. Thanks.
-
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 about 3 years@htmlboss Thanks !
-
Ajay almost 3 years
virtual void myfun() final
in base class is apparently meaningless. -
Ajay almost 3 years
struct Base2 { virtual void f() final;};
is absurd! -
cyb70289 almost 3 yearsThis is the most useful answer here. IMO, the high score answers are correct but as boring as cppreference.
-
VMMF over 2 yearsWhy not public B { void foo() final; }; ? Why putting virtual in class B if we already put final?