What Is the Purpose of the "Final" Keyword in C++11 for Functions

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

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

Does C++ final imply final in all aspects?

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.

Does it make sense to add final keyword to the virtual function in a class that has no base class (is not derived)

If you don't mark the function as virtual and final then the child-class can still implement the function and hide the base-class function.

By making the function virtual and final the child-class can not override or hide the function.

Const vs Final in C++

I suppose this question needs an answer, given the other answers present.

You cannot apply final to variables in C++, so the question "which one is better" can only be answered with "const, because only this can compile".


final specifier was introduced to C++11 and can be applied:

  1. to classes, in this case class cannot be used as a base class
class A final {};
class B: public A {}; //error

  1. to virtual function, to prevent derived classes from overriding it
class A {
virtual void foo() = 0;
};
class B: public A {
void foo() final {}
};
class C: public B {
void foo() {} //error
};

const keyword was in C++ since the very beginning and is used to

  1. mark variables as non-modifiable. Non-member variables must be initialized where they are declared, member must be initialized in constructor initializer list. It's not like final in Java, you cannot assign to it once.
const std::vector<int> v;
v = std::vector<int>{}; //error
v.push_back(1); //error

  1. to mark class member functions as usable with const objects. This also prevents you from modifying class members inside that function
class A {
int n;
public:
int getN() const {return n;}
void setN(int n) {this->n = n;} //cannot be const, modifies a member
};

const A a;
a.getN(); //fine
a.setN(5); //error

Why adding final to a member function of a final class?

final on a virtual function in a final derived class is redundant.

Just like saying virtual on a method marked override is redundant. C++ just is that way sometimes.

What's the point of a final virtual function?

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.

Virtual function efficiency and the 'final' keyword

If fn is defined as final in Bar, the compiler can dispatch calls to fn through a pointer or reference to Bar statically since it knows that Bar::fn is the final overrider. For example, this program fragment:

struct Foo {
virtual void fn();
};

struct Bar : Foo {
void fn() final override;
};

void with_foo(Foo& o) { o.fn(); }
void with_bar(Bar& o) { o.fn(); }

compiles to (See gcc.godbolt.org for details):

with_foo(Foo&):
subq $8, %rsp
movq (%rdi), %rax
call *(%rax)
addq $8, %rsp
ret

with_bar(Bar&):
subq $8, %rsp
call Bar::fn()
addq $8, %rsp
ret

the call in with_foo is dynamically dispatched (call *(%rax) is an indirect call) through the vtable, but the call in with_bar statically dispatches to Bar::fn().

The simplest method to make Bar::fn be the final overrider of Foo::fn without changing behavior is to define it to statically call Foo::fn:

struct Bar : Foo {
void fn() final override { Foo::fn(); }
};

Is final used for optimization in C++?

Is final used for optimization in C++?

It can be, and is.

As noted, it is being used already; see here and here showing the generated code for the override with and without final.

An optimisation along these lines would relate to 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 to determine this, 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. given the OP example, with an automatic object), it could apply such an optimisation anyway, irrespective of whether the method is final or not.

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.



Related Topics



Leave a reply



Submit