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.

Leave a Comment