What's the Point of a Final Virtual Function

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.

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.

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

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(); }
};

Does final imply override?

final does not require the function to override anything in the first place. Its effect is defined in [class.virtual]/4 as

If a virtual function f in some class B is marked with the
virt-specifier final and in a class D derived from B a function D::f
overrides B::f, the program is ill-formed.

That's it. Now override final would simply mean

„This function overrides a base class one (override) and cannot be overriden itself (final).“

final on it's own would impose a weaker requirement.
override and final have independent behavior.


Note that final can only be used for virtual functions though - [class.mem]/8

A virt-specifier-seq shall appear only in the declaration of a
virtual member function (10.3).

Hence the declaration

void foo() final;

Is effectively the same as

virtual void foo() final override;

Since both require foo to override something - the second declaration by using override, and the first one by being valid if and only if foo is implicitly virtual, i.e. when foo is overriding a virtual function called foo in a base class, which makes foo in the derived one automatically virtual. Thus override would be superfluous in declarations where final, but not virtual, occurs.

Still, the latter declaration expresses the intent a lot clearer and should definitely be preferred.

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.



Related Topics



Leave a reply



Submit