What's the point of a final virtual function?

22,303

Solution 1

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 your might mark the functions as final in your derived classes.

Solution 2

For a function to be labelled final it must be virtual, i.e., in C++11 §10.3 para. 2:

[...] For convenience we say that any virtual function overrides itself.

and para 4:

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. [...]

i.e., final is required to be used with virtual functions (or with classes to block inheritance) only. Thus, the example requires virtual to be used for it to be valid C++ code.

EDIT: To be totally clear: The "point" asked about concerns why virtual is even used. The bottom-line reason why it is used is (i) because the code would not otherwise compile, and, (ii) why make the example more complicated using more classes when one suffices? Thus exactly one class with a virtual final function is used as an example.

Solution 3

It doesn't seem useful at all to me. I think this was just an example to demonstrate the syntax.

One possible use is if you don't want f to really be overrideable, but you still want to generate a vtable, but that is still a horrible way to do things.

Solution 4

Adding to the nice answers above - Here is a well-known application of final (very much inspired from Java). Assume we define a function wait() in a Base class, and we want only one implementation of wait() in all its descendants. In this case, we can declare wait() as final.

For example:

class Base { 
   public: 
       virtual void wait() final { cout << "I m inside Base::wait()" << endl; }
       void wait_non_final() { cout << "I m inside Base::wait_non_final()" << endl; }
}; 

and here is the definition of the derived class:

class Derived : public Base {
      public: 
        // assume programmer had no idea there is a function Base::wait() 

        // error: wait is final
        void wait() { cout << "I am inside Derived::wait() \n"; } 
        // that's ok    
        void wait_non_final() { cout << "I am inside Derived::wait_non_final(); }

} 

It would be useless (and not correct) if wait() was a pure virtual function. In this case: the compiler will ask you to define wait() inside the derived class. If you do so, it will give you an error because wait() is final.

Why should a final function be virtual? (which is also confusing) Because (imo) 1) the concept of final is very close to the concept of virtual functions [virtual functions has many implementations - final functions has only one implementation], 2) it is easy to implement the final effect using vtables.

Solution 5

I don't understand the point of introducing a virtual function and immediately marking it as final.

The purpose of that example is to illustrate how final works, and it does just that.

A practical purpose might be to see how a vtable influences a class' size.

struct Base2 {
    virtual void f() final;
};
struct Base1 {
};

assert(sizeof(Base2) != sizeof(Base1)); //probably

Base2 can simply be used to test platform specifics, and there's no point in overriding f() since it's there just for testing purposes, so it's marked final. Of course, if you're doing this, there's something wrong in the design. I personally wouldn't create a class with a virtual function just to check the size of the vfptr.

Share:
22,303
fredoverflow
Author by

fredoverflow

Updated on July 08, 2022

Comments

  • fredoverflow
    fredoverflow almost 2 years

    Wikipedia has the following example on the C++11 final modifier:

    struct Base2 {
        virtual void f() final;
    };
    
    struct Derived2 : Base2 {
        void f(); // ill-formed because the virtual function Base2::f has been marked final
    };
    

    I don't understand the point of introducing a virtual function and immediately marking it as final. Is this simply a bad example, or is there more to it?

  • fredoverflow
    fredoverflow almost 12 years
    Wouldn't it make sense then if final implicitly meant override final?
  • bames53
    bames53 almost 12 years
    I don't see any reason why not, but I also don't see any strong reason to do it since you can already mark functions final override. Perhaps there should be a style warning that requires all final functions to also be marked override like the other virtual and override style warnings.
  • Paul Preney
    Paul Preney almost 12 years
    Respectfully, I totally get the point of the question. The "point" asked about concerns why virtual is even used. The bottom-line reason why it is used is because the code would not otherwise compile AND why make the example more complicated using more classes when one suffices? Thus exactly one class with a virtual final function is used to as an example. QED.
  • Paul Preney
    Paul Preney almost 12 years
    @Luchian Grigore: I added an edit to be completely clear since I did not wrap up my answer with the "bottom-line reason". Perhaps why this question is getting so many comments is due to everyone naturally looking at the example and saying, "Why would anyone use that code?" and not looking at it from the example writer's point-of-view. Most examples are written to be practically useful --this one is not except to make a minimal example showing how it behaves.
  • VSOverFlow
    VSOverFlow almost 12 years
    Final and virtual are two different aspects. It becomes relevant in the override versus overload context. A virtual qualifier implies Run Time Type Inference. A non-virtual implies compile type type inference. When there is overloading involved, and type promotion/conversion involved a non-virtual type can lead to interesting results. Typically though you are encouraged not to write that kind of code.
  • Trass3r
    Trass3r about 11 years
    Well final methods in interfaces would be an example of a final method in a "base" class. Also 'final' yields an error or at least a warning if somebody defines a function with the same name in a subclass. The question is if compilers immediately devirtualize such a case.
  • bames53
    bames53 about 11 years
    @Trass3r It would not be possible to implement a final interface method, because implementing an interface method in C++ requires overriding. Such an unimplementable interface would not be useful.
  • Trass3r
    Trass3r about 11 years
    Yes, that's why you implement it in the interface.
  • bames53
    bames53 about 11 years
    @Trass3r Ah, I see what you're saying. However I don't think this works very well; it doesn't prevent hiding because you can still declare functions of the same name but different signatures in derived classes (and such functions can use default arguments to have effectively the same signature, and there's usually a warning about hiding anyway) and secondly you can only override virtual functions so just not marking the base function virtual would prevent overriding. Finally, using virtual this way seems like obfuscation to me.
  • sasha.sochka
    sasha.sochka almost 11 years
    Why would you want to generate a vtable if compiler doesn't?
  • Mark Ransom
    Mark Ransom about 10 years
    @sasha.sochka I think for example that dynamic_cast won't work without one. But the usual way to ensure a vtable is to make the destructor virtual.
  • idbrii
    idbrii almost 10 years
    @bames53: I doubted your comment about functions using default arguments to have effectively the same signature, but you're right. Also, virtual is required to use final.
  • Troyseph
    Troyseph over 9 years
    This answer actually explains everything instead of simply stating that "otherwise it would be wrong" or "because it is an example", imho this should be accepted as the answer to this question.
  • Antonio
    Antonio about 2 years
    virtual final for a base class method has a use case stackoverflow.com/a/44153376/2436175
  • bames53
    bames53 about 2 years
    @Antonio It doesn't actually prevent hiding. E.g. I can still do this. Using virtual final for this purpose seems janky and I don't think I'd recommend trying it.
  • Antonio
    Antonio about 2 years
    @bames53 The thing is open to debate (there's some consensus on the answer I linked previously), the example you make with the default parameter is a bit extreme, plausible but we can safely say virtual final will cover 90% of the errors. Furthermore, by marking as virtual final a function in the base class we make a clear statement for the developer deriving that class. A bad developer then can always break things. :) I personally use virtual final when I have a base class where most of the members are pure virtual, and I want to warn the developer not to override one specific method.