10

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?

  • For all the same reasons that Java methods are made final? – Ordous Jul 7 '15 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. :) – metamaker Jul 7 '15 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 Jul 7 '15 at 18:49
11

A recap of what the final keyword does: Let's say we have base class A and derived class B. Function f() may be declared in A as virtual, meaning that class B may override it. But then class B might wish that any class which is further derived from B should not be able to override f(). That's when we need to declare f() as final in B. Without the final keyword, once we define a method as virtual, any derived class would be free to override it. The final keyword is used to put an end to this freedom.

An example of why you would need such a thing: Suppose class A defines a virtual function prepareEnvelope(), and class B overrides it and implements it as a sequence of calls to its own virtual methods stuffEnvelope(), lickEnvelope() and sealEnvelope(). Class B intends to allow derived classes to override these virtual methods to provide their own implementations, but class B does not want to allow any derived class to override prepareEnvelope() and thus change the order of stuff, lick, seal, or omit invoking one of them. So, in this case class B declares prepareEnvelope() as final.

  • 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? – metamaker Jul 7 '15 at 18:37
  • Yes, I am sorry, hang on, I am writing an example right now. – Mike Nakis Jul 7 '15 at 18:40
  • @metamaker there you go. – Mike Nakis Jul 7 '15 at 18:46
  • 1
    Really good example, this is the best answer so far. Thx! – metamaker Jul 7 '15 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. – metamaker Jul 7 '15 at 18:53
2

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).

  • How do you plan to override the private method inside your Vehicle class? Didn't you mean protected instead? – Andy Jan 1 '16 at 6:55
  • 3
    @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 Jan 1 '16 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 Jan 1 '16 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 Jan 1 '16 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 Jan 1 '16 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.

  • Why would final and virtual ever be used at the same time? – Robert Harvey Jul 7 '15 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? – metamaker Jul 7 '15 at 18:24
  • @RobertHarvey ABI stability. In any other case, it should probably be final and override. – Deduplicator Jan 1 '16 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 – underscore_d Jul 30 '16 at 23:12

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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