禁止使用返回非常量引用的方法覆盖返回常量引用的虚方法

fla*_*rrr 8 c++ c++14

以下代码编译:

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;
}
Run Code Online (Sandbox Code Playgroud)

如何在编译时禁止重写方法返回引用与返回类型的不同 const 说明符?

提前致谢。

dfr*_*fri 5

以下所有标准参考均指N4659:2017 年 3 月后 Kona 工作草案/C++17 DIS


派生函数的返回类型需要与它覆盖的函数的返回类型协变,反之则不然

[class.virtual]/7 [extract,强调我的]管理:

覆盖函数的返回类型应与覆盖函数的返回类型相同或与函数的类协变如果一个函数D?::?f覆盖了一个函数B?::?f,并且函数的返回类型满足以下条件,则它们是协变的:

  • [...]
  • (7.3) 指针或引用都具有相同的 cv 限定,并且 的返回类型中的类类型D?::?f 具有与的返回类型中的类类型相同或更少的cv 限定B?::?f

使得以下程序格式良好

struct Ret {};

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

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

int main() {}
Run Code Online (Sandbox Code Playgroud)

我们可能会注意到,A::fun底层B对象接口的多态使用将强制接口返回类型的常量性,而以下程序是格式错误的:

struct Ret {};

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

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

int main() { }
Run Code Online (Sandbox Code Playgroud)

它带有以下指导性编译器错误消息(Clang)

error: return type of virtual function 'fun' is 
       not covariant with the return type of the 
       function it overrides
Run Code Online (Sandbox Code Playgroud)

这个要求是很自然的,因为我们可能会注意到,如果接口A允许多态调用非常量Ret&返回,fun()即使派生对象将重载实现为返回 a const Ret&,那么我们将有一种修改const对象的方法(通过多态),即未定义的行为。


有一些自然的解决方法(例如,用Curiosly Recurring Template Pattern替换动态多态,并在 into-base 注入派生类型上进行常量断言),但这些似乎都可以解决XY 问题,并且可能实现只会增加复杂性的模式代码没有任何明显的增益。