Does it make sense to add final keyword to the virtual function in a class that has no base class (is not derived)
Asked Answered
C

3

28

I am reading an awesome awesome C++11 tutorial and the author provides this example while explaining the final keyword:

struct B {
    virtual void f() const final;   // do not override
    virtual void g();
};
struct D : B {
    void f() const;     // error: D::f attempts to override final B::f
    void g();       // OK
};

So does it make sense using here the final keyword? In my opinion you can just avoid using the virtual keyword here and prevent f() from being overridden.

Commandant answered 24/5, 2017 at 8:41 Comment(4)
I don't want to knock it, since a guru may come along and present a use-case where it solves some really obscure compilation error... But it looks like a silly thing to do.Barrus
Possible duplicate of Is there any sense in marking a base class function as both virtual and final?Hospitalization
Actually there are more duplicates, e.g. What's the point of a final virtual function?Agulhas
Why are there 3 close requests? How is the question not legitimate?Tuppeny
T
35

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.

Thad answered 24/5, 2017 at 8:46 Comment(10)
I knew a guru would come along. Although I think this is a bit too much in the way of overhead (that may or may not be elided), just to prevent hiding. +1.Barrus
Apparently there is consensus on the matter, but I for one would like an explanation on how doing nothing useful and breaking another language feature would be considered a benefit.Probability
@Probability its removing the possibility of ambiguity, e.g. in the case of template <DerivedFromB> void doStuff(DerivedFromB & b) { b.f(); }, you can be 100% sure where that f() call goesPendragon
@Pendragon why would you make it a template and perform an unqualified member call if you want a specific f to be called?Probability
@Probability that's a minimal contrived example, but it applies where you have other reasons for the templatePendragon
@Pendragon b.B::f(); will work as you expect even if the static type of b is D.Probability
I think we disagree with what "useful" includes. I consider turning run-time logic errors into compile-time errors "useful". The point is that the writer of B can constrain the writer of D.Pendragon
@Pendragon I have no idea what "runtime logic error" you're talking about. You want to call B::f, just call it. I appreciate your effort at coming up with an example, but here there is simply no point in writing a completely general b.f() (i.e. call the statically most-derived f), only to cripple the ability to actually hide f afterwards. The result is the same, but now the developper of D and D's descendants gets that virtual kludge and cannot use f anymore.Probability
Let us continue this discussion in chat.Pendragon
@Caleth: class D : public B { virtual void f(int=0); }. Who says I can't "override" B::f ? Quentin's solution b.B::f() does work as intended here.Cupboard
S
11

Yes! In the example you provide, the final keyword prevents any derived classes from overriding f() as you correctly say. If the function is non-virtual, D:f() is allowed to hide the base class version of the function:

struct B {
    void f() const;   // do not override
    virtual void g();
};
struct D : B {
    void f() const; // OK!
    void g();       // OK
};

By making f() a virtual and final function, any attempt at overriding or hiding causes a compile error.

Stonecrop answered 24/5, 2017 at 8:48 Comment(0)
P
3

Your intuition is right: making a function virtual only to immediately cap it with final has no benefit over a non-virtual function. This is just a short sample snippet to demonstrate the feature.

Additionally, as described in other answers, this actually breaks function hiding -- you won't ever be able to have an f function with the same parameter list in D or any of its derived classes.
This is a trade-off to be done when you decide to cap f in your model. Since there is no way to perform an actual virtual call here, you essentially have the disadvantage and no benefit.

Probability answered 24/5, 2017 at 8:45 Comment(6)
I thought of name hiding. Thus you prevent the derived class to hide f(). If you declare f() without virtual keyword, it can be hidden in derived class I guess.Commandant
Comments are, as always, much appreciated with downvotes.Probability
I think the downvotes are due to your attitude towards disabling name hiding. I suppose this feature can actually be used for some special purpose, although I can't name any such purpose off the top of my head.Agulhas
@Agulhas well, anything to do with static polymorphism for a start. I don't know, disabling arbitrary features because you don't know a use for them and claiming it's for the better sounds very short-sighted to me. Is there a goto-like taboo on function hiding that I'd have missed?Probability
By the feature I don't mean "function name hiding" — I mean "disabling function name hiding". Of course I do know uses for name hiding itself.Agulhas
@Agulhas oh, my bad :)Probability

© 2022 - 2024 — McMap. All rights reserved.