17

I know that final keyword is used to prevent virtual method from being overriden by derived classes. However, I can't find any useful example when I should really use final keyword with virtual method. Even more, it feels like usage of final with virtual methods is a bad smell since it disallows programmers to extend class in future.

My question is next:

Is there any useful case when I really should use final in virtual method declaration?

3
  • For all the same reasons that Java methods are made final?
    – Ordous
    Commented Jul 7, 2015 at 18:14
  • In Java all methods are virtual. Final method in base class can improve performance. C++ has non-virtual methods, so it is not a case for this language. Do you know any other good cases? I would like to hear them. :)
    – dmytroy
    Commented Jul 7, 2015 at 18:15
  • Guess I'm not very good at explaining things - I was trying to say the exact same thing as Mike Nakis.
    – Ordous
    Commented Jul 7, 2015 at 18:49

3 Answers 3

19

An example of why you would need such a thing:

Suppose class A defines a virtual function prepareEnvelope().

And suppose that class B extends A and overrides prepareEnvelope(), implementing it as a sequence of calls to its own virtual methods stuffEnvelope(), lickEnvelope() and sealEnvelope().

Obviously, since these new methods are virtual, class B intends to allow derived classes to override them to provide their own implementations; however class B probably does not want to allow a derived class to also override prepareEnvelope() and thus potentially change the order of stuff, lick, seal, or omit invoking one of them.

So, in this case class B would declare prepareEnvelope() as final.

The example above is a case of the template method pattern (https://en.wikipedia.org/wiki/Template_method_pattern) where class B implements prepareEnvelope() as a template method to achieve a certain goal, and presumably also contains other functionality (e.g. fields) to support that goal. Any derived class should conform to that template, otherwise the supported functionality is provided in vain, and in certain cases failure to use that functionality may cause malfunction. (If the lickEnvelope() method is not invoked, then no saliva will be consumed, so who knows, the saliva container might overflow.) So, if you want to build a class which deviates from the pattern established by B, then you should not be deriving from B, you should be deriving from the basemost class A.

Another example:

The same thing can be seen in a more simple scenario which most programmers encounter at some point: Let's say the basemost class A has a cleanUp() method, and derived class B overrides cleanUp() to perform some very important actions which absolutely must be performed or else the Universe will self-destruct. In this case, class B may not want to leave it up to derived classes to decide whether their overrides of cleanUp() will invoke B::cleanUp() or not. To this effect, class B may make cleanUp() final, and declare an empty protected virtual method onCleanUp() which is invoked from within cleanUp() to allow descendants to override it in order to do their own cleanup. This means that when cleanUp() is invoked on the object, method B::cleanUp() will always be invoked, and thus the Universe will be saved, while overrides of onCleanUp() may forget invoking B::onCleanUp(), and nothing bad will happen, because it is empty.

Generally:

In the general case, a class declares a method as final if the class contains functionality which requires that the method must be invoked and must work exactly as defined. In these cases, derived classes must not be allowed to override the method, because the overrides may work differently, or they may omit invoking the base method.

7
  • First, thank you for the answer but isn't that exectly what I have written in a first sentence of my question? What I really need is a case when class B might wish that any class which is further derived from B should not be able to override f()? Is there any real world case where such class B and method f() exists and fits well?
    – dmytroy
    Commented Jul 7, 2015 at 18:37
  • Yes, I am sorry, hang on, I am writing an example right now.
    – Mike Nakis
    Commented Jul 7, 2015 at 18:40
  • @metamaker there you go.
    – Mike Nakis
    Commented Jul 7, 2015 at 18:46
  • 1
    Really good example, this is the best answer so far. Thx!
    – dmytroy
    Commented Jul 7, 2015 at 18:46
  • 1
    Then thank you for a wasted time. I couldn't find a good example on the Internet, wasted a lot of time searching. I would put +1 for the answer but I can't do it since I have low reputation. :( Maybe later.
    – dmytroy
    Commented Jul 7, 2015 at 18:53
6

It's often useful from a design perspective to be able to mark things as unchanging. In the same way the const provides compiler guards and indicates that a state should not change, final can be used to indicate that behavior should not change any further down the inheritance hierarchy.

Example

Consider a video game where vehicles take the player from one location to another. All vehicles should check to make sure they are traveling to a valid location prior to departure (making sure the base at the location is not destroyed, e.g.). We can start off using the non-virtual interface idiom (NVI) to guarantee that this check is made regardless of the vehicle.

class Vehicle
{
public:
    virtual ~Vehicle {}

    bool transport(const Location& location)
    {
        // Mandatory check performed for all vehicle types. We could potentially
        // throw or assert here instead of returning true/false depending on the
        // exceptional level of the behavior (whether it is a truly exceptional
        // control flow resulting from external input errors or whether it's
        // simply a bug for the assert approach).
        if (valid_location(location))
            return travel_to(location);

        // If the location is not valid, no vehicle type can go there.
        return false;
    }

private:
    // Overridden by vehicle types. Note that private access here
    // does not prevent derived, nonfriends from being able to override
    // this function.
    virtual bool travel_to(const Location& location) = 0;
};

Now let's say we have flying vehicles in our game, and something that all flying vehicles require and have in common is that they must go through a safety inspection check inside the hangar prior to take-off.

Here we can use final to guarantee that all flying vehicles will go through such an inspection and also communicate this design requirement of flying vehicles.

class FlyingVehicle: public Vehicle
{
private:
    bool travel_to(const Location& location) final
    {
        // Mandatory check performed for all flying vehicle types.
        if (safety_inspection())
            return fly_to(location);

        // If the safety inspection fails for a flying vehicle, 
        // it will not be allowed to fly to the location.
        return false;
    }

    // Overridden by flying vehicle types.
    virtual void safety_inspection() const = 0;
    virtual void fly_to(const Location& location) = 0;
};

By using final in this way, we are effectively sort of extending the flexibility of the non-virtual interface idiom to provide uniform behavior down the inheritance hierarchy (even as an afterthought, countering the fragile base class problem) to virtual functions themselves. Furthermore, we buy ourselves wiggle room to make central changes that affect all flying vehicle types as an afterthought without modifying each and every flying vehicle implementation that exists.

This is one such example of using final. There are contexts you will encounter where it simply doesn't make sense for a virtual member function to be overridden any further -- to do so might lead to a brittle design and a violation of your design requirements.

That's where final is useful from a design/architectural perspective.

It's also useful from an optimizer's perspective since it provides the optimizer this design information that allows it to devirtualize virtual function calls (eliminating the dynamic dispatch overhead, and often more significantly, eliminating an optimization barrier between caller and callee).

Question

From the comments:

Why would final and virtual ever be used at the same time?

It doesn't make sense for a base class at the root of a hierarchy to declare a function as both virtual and final. That seems quite silly to me, as it would make both compiler and human reader have to jump through unnecessary hoops which can be avoided by simply avoiding virtual outright in such a case. However, subclasses inherit virtual member functions like so:

struct Foo
{
   virtual ~Foo() {}
   virtual void f() = 0;
};

struct Bar: Foo
{
   /*implicitly virtual*/ void f() final {...}
};

In this case, whether or not Bar::f explicitly uses the virtual keyword, Bar::f is a virtual function. The virtual keyword then becomes optional in this case. So it might make sense for Bar::f to be specified as final, even though it is a virtual function (final can only be used for virtual functions).

And some people may prefer, stylistically, to explicitly indicate that Bar::f is virtual, like so:

struct Bar: Foo
{
   virtual void f() final {...}
};

To me it's kind of redundant to use both virtual and final specifiers for the same function in this context (likewise virtual and override), but it's a matter of style in this case. Some people might find that virtual communicates something valuable here, much like using extern for function declarations with external linkage (even though it's optional lacking other linkage qualifiers).

6
  • How do you plan to override the private method inside your Vehicle class? Didn't you mean protected instead?
    – Andy
    Commented Jan 1, 2016 at 6:55
  • 5
    @DavidPacker private doesn't extend to overridding (a bit counter-intuitive). Public/protected/private specifiers for virtual functions only apply to callers and not to overriders, put crudely. A derived class can override virtual functions from its base class regardless of its visibility.
    – user204677
    Commented Jan 1, 2016 at 7:15
  • @DavidPacker protected might make a bit more intuitive sense. I just prefer to reach for the lowest-visibility possible whenever I can. I think the reason the language is designed this way is that, otherwise, private virtual member functions would make no sense whatsoever outside the context of friendship, since no class but a friend would then be able to override them if access specifiers mattered in the context of overriding and not just calling.
    – user204677
    Commented Jan 1, 2016 at 7:17
  • I thought having it set to private would not even compile. For example neither Java nor C# allow that. C++ surprises me every day. Even after 10 years of programming.
    – Andy
    Commented Jan 1, 2016 at 9:02
  • @DavidPacker It tripped me up too when I first encountered it. Maybe I should just make it protected to avoid confusing others. I ended up putting a comment, at least, describing how private virtual functions can still be overridden.
    – user204677
    Commented Jan 1, 2016 at 9:07
0
  1. It enables lot of optimisations, because it may be known at compile time which function is called.

  2. Be careful throwing the word "code smell" around. "final" doesn't make it impossible to extend the class. Double click on the "final" word, hit backspace, and extend the class. HOWEVER final is an excellent documentation that the developer doesn't expect you to override the function, and that because of that the next developer should be very careful, because the class might stop working properly if the final method gets overridden that way.

4
  • 1
    Why would final and virtual ever be used at the same time? Commented Jul 7, 2015 at 18:24
  • 1
    It enables lot of optimisations, because it may be known at compile time which function is called. Can you explain how or provide a reference? HOWEVER final is an excellent documentation that the developer doesn't expect you to override the function, and that because of that the next developer should be very careful, because the class might stop working properly if the final method gets overridden that way. Isn't that a bad smell?
    – dmytroy
    Commented Jul 7, 2015 at 18:24
  • @RobertHarvey ABI stability. In any other case, it should probably be final and override. Commented Jan 1, 2016 at 22:13
  • @metamaker I had the same Q, discussed in comments here - programmers.stackexchange.com/questions/256778/… - & funnily have stumbled into several other discussions, only since asking! Basically, it's about if an optimising compiler/linker can determine whether a reference/pointer might represent a derived class & thus need a virtual call. If the method (or class) provably can't be overridden beyond the reference's own static type, they can devirtualise: call directly. If there's any doubt - as often - they must call virtually. Declaring final can really help them Commented Jul 30, 2016 at 23:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.