以下代码编译:
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;
}
在编译期间,如何禁止使用不同的const说明符覆盖方法返回的引用,以用于返回类型?
谢谢。
答案 0 :(得分:5)
以下所有标准参考文献均引用N4659: March 2017 post-Kona working draft/C++17 DIS。
受[class.virtual]/7的约束[摘录,强调我的]:
覆盖函数的返回类型应或相同 到覆盖函数的返回类型或 covariant 与 函数的类。如果函数
D::f
覆盖了 函数B::f
,如果以下情况,则函数的返回类型是协变的 它们满足以下条件:
- [...]
- (7.3)指针或引用具有相同的cv限定,并且返回类型
D::f
中的类类型具有相同的 cv-qualification小于或等于类别中的类类型 返回类型B::f
。
使以下程序格式正确
struct Ret {};
struct A {
virtual const Ret& fun() = 0;
};
struct B : public A {
Ret& fun() override { /* ... */ }
};
int main() {}
我们可能会注意到,底层A::fun
对象的B
接口的多态用法将强制该接口的返回类型保持不变,而以下程序格式不正确:>
struct Ret {};
struct A {
virtual Ret& fun() = 0;
};
struct B : public A {
const Ret& fun() override { /* ... */ }
};
int main() { }
随附以下说明性编译器错误消息(Clang)
error: return type of virtual function 'fun' is not covariant with the return type of the function it overrides
这个要求很自然,因为我们可能会注意到,如果接口A
if 可以多态调用非常量Ret&
并返回fun()
,即使派生对象通过返回const Ret&
来实现重载,那么我们将有一种方法(通过多态性)修改const
对象,这是未定义的行为。
有自然的解决方法(例如,将Curiosly Recurring Template Pattern和动态性多态性替换为注入基注入的派生类型中的常量声明),但这些方法似乎都可以解决an XY problem并可能实现模式只会增加代码的复杂性而没有任何明显的收获。