C++ Logo

std-discussion

Advanced search

Re: Why no implicit declaration of necessary overrides in final classes?

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Sat, 15 Aug 2020 11:37:32 -0400
On Sat, Aug 15, 2020 at 5:01 AM Eyal Rozenberg via Std-Discussion
<std-discussion_at_[hidden]> wrote:
>
> Consider the following code:
> ```
> class A {
> virtual int foo() = 0;
> };
>
> class B final : A {
> int foo() override; // (*)
> };
>
> int B::foo() { return 123; }
> ```
> ... which fails to compile if we remove the declaration (*).
>
> Since `B` is a final class, it must necessarily have all methods defined
> immediately or by inheritance. Specifically, we must define all `B`
> methods which are not defined for its (single) base class `A`.
>
> Why, then, must `B` declare `foo()` explicitly?

To my knowledge, there is no precedent for implicit declarations of
things that need user-provided *definitions* in C++. Pretty much
everything that C++ implicitly declares is implicitly defined too
(either with an implementation or deleted): default constructors,
copy/move constructors/assignment operators, destructors, etc.

If it needs an explicit definition, then it needs an explicit
declaration too. If it is implicitly declared, then it is implicitly
defined. That's just how C++ works.

> Why is the implicit need
> for the definition not sufficient to allow this code to compile? I mean,
> I assume the standard requires an explicit declaration here, but what is
> the rationale for this requirement?
>
> An obvious counter-rationale is DRY: If class A has N virtual methods
> and M final subclasses, we'll have to write M*N redundant declarations.
> And these redundant declarations also visually "mask", to some extent,
> the declarations of those methods which are specific to B.

Code is read more than it is written. In a non-modules world,
definitions and declarations in classes are often separated. As such,
if you want to know what a class can do, you often look at the class
definition and see its list of methods.

If you want to see what functionality a derived class directly
provides, you look at the class definition. Outside of the few,
specific implicit declarations, the interface a derived class
implements is stated plainly and obviously in the class definition.

DRY is intended to be for removing information that you *know* within
the locality of the context you're reading. The interface provided by
a base class is not local information, so restating it is not
especially redundant.

And in a modules world where member function declarations are usually
definitions too, this serves no purpose.

Oh and it should be noted that presently, a compiler can issue a
warning (or error) if you don't declare an override for a pure-virtual
function in a `final` class by the end of the class's definition.
Clang does this, even without special warnings settings. If the change
you seek were to happen, such warnings could no longer be issued. At
least, not by the compiler; it'd have to be a link-time check, which
would be far harder to implement.

So basically, if you *forget* to provide a definition for an implicit
declaration, the compiler may never tell you.

Received on 2020-08-15 10:41:07