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.
All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.
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 functionB::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 ofB::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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With