C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Allow non-virtual methods to be final

From: Steve Thomas <steve.p.thomas_at_[hidden]>
Date: Thu, 5 Jan 2023 16:19:06 -0800
On Thu, Jan 5, 2023 at 2:15 PM Brian Bi via Std-Proposals <
std-proposals_at_[hidden]> wrote:

>
>
> On Thu, Jan 5, 2023 at 5:09 PM Frederick Virchanza Gotham <
> cauldwell.thomas_at_[hidden]> wrote:
>
>> On Thu, Jan 5, 2023 at 10:01 PM Brian Bi <bbi5291_at_[hidden]> wrote:
>>
>> > No.
>> >
>> > There's no legitimate reason to restrict what the author of B can make
>> > one of its non-virtual functions do. As such, there should not be a
>> > language-level mechanism for it.
>>
>> The following program fails to compile:
>>
>> struct A {
>> virtual int Func(void) final { return 5; }
>> };
>>
>> struct B : A {
>> int Func(void) { return 6; }
>> };
>>
>> int main(void)
>> {
>> B obj;
>> }
>>
>> Note here that the person who wrote 'B' didn't necessarily know that
>> 'A' had a virtual function called 'Func', but nonetheless 'B' is
>> restricted in what it can do. So it won't be that much different
>> restricting non-virtual functions also.
>>
>
> I think you meant to send this to the list, not to me.
>
> Sure, if you declare a virtual method `final`, then you restrict what
> derived classes can do, but the difference is that there's actually a
> legitimate reason for the restriction. If I have
>
> int foo(A& a) { return a.Func(); }
>
> and `A::Func` is final, then the compiler can devirtualize the call. In
> addition, the writer of this code can rely on the guarantee that `a.Func()`
> has the same value and side effects as `a.A::Func()`. If any other
> functions in `A` call `A::Func`, then they, too, can rely on such
> guarantees.
>
> On the other hand, if `Func` is non-virtual, then those guarantees already
> hold; having the ability to prevent a derived class from declaring a method
> with the same name does not strengthen them. As such, it is a restriction
> that gives nothing in return.
>
> There are two things going on here:

1) final prevents calls to Func() being delegated to subclasses from the
code under A's control (i.e., itself and parent scopes)
2) final prevents the name (actually the signature) from being reused in
subclass scopes

1) is a legitimate goal of final. 2) is not.

So, the real question is: why does the specification make a half-assed
attempt at making 2) true if it's not a goal of final? I say half-assed,
since if you are really desperate to hide the name and reuse it in
subclasses, you can workaround by adding a trivially defaulted parameter to
the signature, at which point the compiler will stop complaining, even with
calls that use exactly the same signature as before. If the point of final
is not to restrict what you can do in subclasses, then why does the
specification do exactly that?

Received on 2023-01-06 00:19:19