Note that non-inheritable classes exist in C++11 using the final keyword, specified before the : base1, base2, ..., baseN inheritance list or before the opening { if the class inherits from nothing:
class Final final { };
class Derived : public Final { }; // ERROR
With a little macro magic and some compiler-detection effort this can be abstracted away to work, or at worst do nothing, on all compilers.
Answer from Jeff Walden on Stack OverflowVideos
Note that non-inheritable classes exist in C++11 using the final keyword, specified before the : base1, base2, ..., baseN inheritance list or before the opening { if the class inherits from nothing:
class Final final { };
class Derived : public Final { }; // ERROR
With a little macro magic and some compiler-detection effort this can be abstracted away to work, or at worst do nothing, on all compilers.
Well, for this program (pleasse provide correct, compilable examples)
#include <iostream>
class Temp
{
private:
~Temp() {}
friend class Final;
};
class Final : virtual public Temp
{
public:
void fun() { std::cout<<"In base"; }
};
class Derived : public Final {};
int main() {
Derived obj;
obj.fun();
}
Comeau Online says
Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions
"ComeauTest.c", line 16: error: "Temp::~Temp()" (declared at line 6) is inaccessible
class Derived : public Final {
^
detected during implicit generation of "Derived::Derived()" at line
21
"ComeauTest.c", line 16: error: "Temp::~Temp()" (declared at line 6) is inaccessible
class Derived : public Final {
^
detected during implicit generation of "Derived::~Derived()" at line
21
2 errors detected in the compilation of "ComeauTest.c".
Since, when in doubt, I always trust como (I have only ever found one error in it, but many in other compilers), I suppose VC9 (which accepts the code) is in error. (From that void main() I suppose you use VC, too.)
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!
};
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 finalIt 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
overridenorfinalare 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
The reason I am asking this is because final functions become qualified for de-virtualization, which is a great optimization.
Do they? "De-virtualization" is not part of the C++ standard. Or at least, not really.
De-virtualization is merely a consequence of the "as if" rule, which states that the implementation can do whatever it likes so long as the implementation behaves "as if" it is doing what the standard says.
If the compiler can detect at compile-time that a particular call to a virtual member function, through a polymorphic type, will undeniably call a specific version of that function, then it is allowed to avoid using the virtual dispatching logic and calling the function statically. That's behaving "as if" it had used the virtual dispatching logic, since the compiler can prove that this is the function that would have been called.
As such, the standard does not define when de-virtualization is allowed/forbidden. A compiler, upon inlining a function that takes a pointer to a base class type, may find that the pointer being passed is pointing to a stack variable local declared in the function that it is being inlined within. Or that the compiler can trace down a particular inline/call graph to the point of origin for a particular polymorphic pointer/reference. In those cases, the compiler can de-virtualize calls into that type. But only if it's smart enough to do so.
Will a compiler devirtualize all virtual function calls to a final class, regardless of whether those methods are declared final themselves? It may. It may not. It may not even devirtualize any calls to methods declared final on the polymorphic type. That's a valid (if not particularly bright) implementation.
The question you're asking is implementation specific. It can vary from compiler to compiler.
However, a class being declared final, as you pointed out, ought to be sufficient information for the compiler to devirtualize all calls to pointers/references to the final class type. If a compiler doesn't do so, then that's a quality-of-implementation issue, not a standards one.
To quote the draft C++ standard from here [class.virtual/4]:
If a virtual function
fin some classBis marked with the virt-specifierfinaland in a classDderived fromBa functionD::foverridesB::f, the program is ill-formed.
And here [class/3]:
If a class is marked with the class-virt-specifier
finaland it appears as a base-type-specifier in a base-clause (Clause [class.derived]), the program is ill-formed.
So, in answer to the question;
Does a
finalclassimplicitly imply itsvirtualfunctions to befinalas well? Should it? Please clarify.
So, at least not formally. Any attempt to violate either rule will have the same result in both cases; the program is ill-formed and won't compile. A final class means the class cannot be derived from, so as a consequence of this, its virtual methods cannot be overridden.
Should it? At least formally, probably not; they are related but they are not the same thing. There is also no need formally require the one to imply the other, the effect follows naturally. Any violations have the same result, a failed compilation (hopefully with appropriate error messages to distinguish the two).
To touch on your motivation for the query and the de-virtualization of the virtual calls. This is not always immediately affected by the final of the class nor method (albeit they offer help), the normal rules of the virtual functions and class hierarchy apply.
If the compiler can determine that at runtime a particular method will always be called (e.g. with an automatic object, i.e. "on the stack"), it could apply such an optimisation anyway, irrespective of the method being marked final or not. These optimisations fall under the "as-if" rule, that allow the compiler to apply any transformation so long as the observable behaviour is as-if the original code had been executed.
The final keyword has several usages in Java. It corresponds to both the sealed and readonly keywords in C#, depending on the context in which it is used.
Classes
To prevent subclassing (inheritance from the defined class):
Java
public final class MyFinalClass {...}
C#
public sealed class MyFinalClass {...}
Methods
Prevent overriding of a virtual method.
Java
public class MyClass
{
public final void myFinalMethod() {...}
}
C#
public class MyClass : MyBaseClass
{
public sealed override void MyFinalMethod() {...}
}
As Joachim Sauer points out, a notable difference between the two languages here is that Java by default marks all non-static methods as virtual, whereas C# marks them as sealed. Hence, you only need to use the sealed keyword in C# if you want to stop further overriding of a method that has been explicitly marked virtual in the base class.
Variables
To only allow a variable to be assigned once:
Java
public final double pi = 3.14; // essentially a constant
C#
public readonly double pi = 3.14; // essentially a constant
As a side note, the effect of the readonly keyword differs from that of the const keyword in that the readonly expression is evaluated at runtime rather than compile-time, hence allowing arbitrary expressions.
It depends on the context.
- For a
finalclass or method, the C# equivalent issealed. - For a
finalfield, the C# equivalent isreadonly. - For a
finallocal variable or method parameter, there's no direct C# equivalent.
As the implementer of GCC's __is_final intrinisic (for PR 51365) I'm pretty sure it can't be done in a library, it needs compiler support.
You can do some very clever things with C++11's SFINAE for expressions feature but to detect whether a class is final you'd need to derive from it, and instantiate the derived type, in a template argument deduction context, but deriving from a class is done in a declaration not an expression.
Also, you should think about whether you only want to know if the final pseudo-keyword was used, or if a class is un-derivable for other reasons, such as having only private constructors.
Type traits are usually implemented using the SFINAE idiom, which places a potentially ill-formed expression inside a function template declaration. Substituting the typename in question into the declaration results in an error, but the error is suppressed in that context, so the declaration is either used or not. But a fallback overload backs up the potentially missing declaration. Another bit of code accesses the function to detect whether the sensitive overload or only the backup was instantiated.
This won't work for final because it can only cause failure during template instantiation of a class. There's no way to overload classes, and no way to tentatively define a class that will fail but not halt compilation in case it's derived from final.
Standard quote, C++11 §14.8.2/8:
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed. — end note ]