Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disallowing overriding virtual method returning const reference with a method returning non-const reference

Tags:

c++

c++14

Following code compiles:

struct Ret {};

struct A
{
    virtual const Ret& fun() = 0; 
};

struct B : public A
{
    Ret& fun() override
    {
        static Ret ret;
        return ret;
    }
};

int main()
{
    B b;
}

How can I disallow overriding method returning reference with a different const specifier for return type during compile time?

Thanks in advance.

like image 628
flamasterrr Avatar asked Aug 25 '20 09:08

flamasterrr


1 Answers

All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.


The return type of a derived function needs to be covariant with the return type of the function it overrides, but not the other way around

As governed by [class.virtual]/7 [extract, emphasis mine]:

The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. If a function D​::​f overrides a function B​::​f, the return types of the functions are covariant if they satisfy the following criteria:

  • [...]
  • (7.3) both pointers or references have the same cv-qualification and the class type in the return type of D​::​f has the same cv-qualification as or less cv-qualification than the class type in the return type of B​::​f.

such that the following program is well-formed

struct Ret {};

struct A {
    virtual const Ret& fun() = 0;
};

struct B : public A {
    Ret& fun() override { /* ... */ }
};

int main() {}

where we may note that polymorphic usage of the A::fun interface of an underlying B object will enforce the constness of the return type of the interface, whereas the following program is ill-formed:

struct Ret {};

struct A {
    virtual Ret& fun() = 0;
};

struct B : public A {
    const Ret& fun() override { /* ... */ }
};

int main() { }

which comes with the following instructive compiler error message (Clang)

error: return type of virtual function 'fun' is 
       not covariant with the return type of the 
       function it overrides

This requirement comes natural, as we may note that if the interface A would allow polymorphically invoking the non-const Ret&-returning fun() even if a derived object implements the overload as returning a const Ret&, then we would have a way modify const object (through polymorphism), which is undefined behaviour.


There are naturally workarounds (e.g. replacing dynamic polymorphism with the Curiosly Recurring Template Pattern and constness assertions on the into-base injected derived type) but these would arguably all seem to address an XY problem and are likely to implement patterns that only increase the complexity of the code without any apparent gain.

like image 149
dfrib Avatar answered Nov 15 '22 06:11

dfrib