为什么以下代码是协方差错误?不是T *
与void *
协变......?
struct Base { virtual void *foo(); };
struct Derived : Base { int *foo(); };
海湾合作委员会说:
invalid covariant return type for 'virtual int* Derived::foo()'
答案 0 :(得分:7)
[class.virtual] / p7,强调我的:
覆盖函数的返回类型应与...相同 被覆盖函数的返回类型或协变与 功能的类。如果函数
D::f
覆盖函数B::f
,函数的返回类型是协变的 满足以下标准:
- 都指向类的指针,两者都是类的左值引用,或者两者都是类的右值引用 [脚注省略]
- [...]
来自D&E的第294-5页:
考虑到替代方案后,我们决定允许 覆盖
B*
D*
和B&
覆盖D&
其中B
是{D
的可访问基础。此外,还可以添加const
或 减去任何安全的地方。我们决定不放宽规则 允许技术上可行的转换,例如D
到可访问的转换 基数B
,D
到X
D
有转化,int*
到void*
,double
到int
等我们感受到的好处 通过覆盖允许这样的转换不会超过 实施成本和混淆用户的可能性。
答案 1 :(得分:1)
不允许使用void*
和T*
之间的协方差,因为:
<强> 1。缺乏一致性。
目前的协方差方法很容易理解,也不会引起混淆
想象一下void*
类型的协方差是允许的。对于1阶段的推导是好的,但它会产生混乱。 e.g:
struct void_ { virtual void* foo (); };
struct int_ : void_ { virtual int* foo (); };
struct double_ : int_ { virtual double* foo (); }; // int* to double* or void* to double*
在struct double_
的第3层次结构中,用户会感到困惑,即使double*
到int*
不可能,为什么代码仍然在编译?只有在检查了最顶级的课程void_
之后,才知道这是因为double*
到void*
是“协变”。编译器也是如此: - )
<强> 2。引用问题
如果是课程,则可以返回B&
/ D*
/ DD*
。但void&
因此int&
等无法实现同样的目标。
第3。混合协方差
如果允许void*
,则无意中允许跟随。
struct void_ { virtual void* foo (); };
struct Base : void_ { virtual Base* foo (); };
struct Derived : Base { virtual int* foo (); }; // Look at `int*`
这会增加混乱。
答案 2 :(得分:0)
协变返回类型功能是指派生类为重写函数提供更具体/更窄的返回类型。派生类返回类型被称为协变。
int *不是void *类型,而像这样的东西确实描述了协变返回类型:
struct Base {
virtual void *foo();
virtual Base* func();
};
struct Derived : Base {
// int *foo();
Derived* func(); //COVARIANT RETURN TYPE
};