I agree, we don't need to proceed further with this suggestion.  The feedback given on this thread illustrates alternative approaches that exist today, so no need to add to language complexity.

On Fri, Nov 11, 2022 at 12:14 AM Jason C <jason.cipriani@gmail.com> wrote:
I don't think this makes sense as a language feature.

The goal seems to be to catch and/or prevent accidentally overridden methods. That makes more sense as a compiler warning. GCC at least already implements that:

    gcc -Wsuggest-override

Will warn if a method without an "override" keyword is in fact an override.

    gcc --Wsuggest-override -Werror=suggest-override

Will produce an error in the same case, which is exactly the end effect that you're looking for.

For MS's CL compiler (MSVC) you can enable warning C26433 (or treat it as an error).

Warnings can always be enabled per file, in both compilers.

So this doesn't really need to be in the language.
 
Jason



On Mon, Nov 7, 2022 at 11:24 AM Paul Fee via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hello,

The "final" and "override" specifiers can be useful to ensure code using inheritance is implemented as expected.  However there are some gaps where I find some features lacking, I can't express some approaches nor get the compiler to confirm my assumptions.  When refactoring large codebases, one may wish to make an isolated API change but inadvertently changes code that's part of a class hierarchy.  Some additional specifiers may allow developers to proceed with caution, protecting them before breaking functionality.

Example:

struct Base
{
  virtual bool state() { return false; }
};

struct Derived : public Base
{
  bool state() { return s; }
private:
  bool s = false;
}

One may opt to refactor state() to make it a const method, without noticing there's also an implementation in the base class as "virtual" is only necessary in the base class.  Such a change should be applied consistently throughout the hierarchy.  I'd like the compiler to confirm that the member function does NOT override a base class function, then I'd be able to follow up with broader refactoring knowing the impact of the change is limited to just one class.  The final specifier means I don't need to look further down the class hierarchy, but I don't have a specifier that ensures I don't need to look up the hierarchy.

Step 1: If this still compiles, then we know there'll be no surprises when changing the API.
struct Derived final : public Base
{
  bool state() !override { return s; }
private:
  bool s = false;
}

Step 2: state function signature can be safely changed.
struct Derived final : public Base
{
  bool state() const !override { return s; }
private:
  bool s = false;
}

Here !override is use as example syntax, but that was just to illustrate the idea.  When refactoring, step 1 would fail to compile because Derived::state() does override Base::state().  This alerts the developer to the danger of only changing the derived class.

Would it be reasonable to enhance the set of specifiers so that more scenarios can be expressed, allowing the compiler to confirm if the developer's assumptions are correct?  For example:

* function must/must not override a base class function
* function must/must not be part of a group of overloads
* function must/must not be virtual

Thanks,
Paul
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals