为什么我不能有 return 类型与 void* 协变?
Why can't I have return types covariant with void*?
为什么下面的代码是协方差错误? T *
不是与 void *
... 协变的吗?
struct Base { virtual void *foo(); };
struct Derived : Base { int *foo(); };
海湾合作委员会说:
invalid covariant return type for 'virtual int* Derived::foo()'
[class.virtual]/p7,强调我的:
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:
- both are pointers to classes, both are lvalue references to classes, or both are rvalue references to classes [footnote omitted]
- [...]
来自 D&E 的第 294-5 页:
Afer some consideration of the alternatives, we decided to allow
overriding of a B*
by a D*
and of a B&
by a D&
where B
is an
accessible base of D
. In addition, const
can be added or
subtracted wherever that is safe. We decided not to relax the rules to
allow technically feasible conversions such as a D
to an accessible
base B
, a D
to an X
for which D
has a conversion, int*
to
void*
, double
to int
, etc. We felt that the benefits from
allowing such conversions through overriding would not outweigh the
implementation cost and the potential for confusing users.
协变 return 类型特征是派生的 class 为重写函数提供更多 specific/narrower return 类型。派生的 class return 类型被认为是协变的。
int* 不是 void* 类型,而像这样的东西确实描述了协变 return 类型:
struct Base {
virtual void *foo();
virtual Base* func();
};
struct Derived : Base {
// int *foo();
Derived* func(); //COVARIANT RETURN TYPE
};
void*
和 T*
之间的协方差是不允许的,因为:
1.缺乏一致性.
当前的协方差方式很容易理解,不会造成混淆。
试想 void*
类型的协方差是允许的。对于 1 阶段的推导很好,但它会造成混乱。例如:
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*
都不可能,为什么代码还在编译呢?查了最上面的classvoid_
才知道是因为double*
到void*
是"covariant"。编译器也一样:-)
2。引用问题
在 classes 的情况下,返回 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*`
这会造成混乱。
为什么下面的代码是协方差错误? T *
不是与 void *
... 协变的吗?
struct Base { virtual void *foo(); };
struct Derived : Base { int *foo(); };
海湾合作委员会说:
invalid covariant return type for 'virtual int* Derived::foo()'
[class.virtual]/p7,强调我的:
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:
- both are pointers to classes, both are lvalue references to classes, or both are rvalue references to classes [footnote omitted]
- [...]
来自 D&E 的第 294-5 页:
Afer some consideration of the alternatives, we decided to allow overriding of a
B*
by aD*
and of aB&
by aD&
whereB
is an accessible base ofD
. In addition,const
can be added or subtracted wherever that is safe. We decided not to relax the rules to allow technically feasible conversions such as aD
to an accessible baseB
, aD
to anX
for whichD
has a conversion,int*
tovoid*
,double
toint
, etc. We felt that the benefits from allowing such conversions through overriding would not outweigh the implementation cost and the potential for confusing users.
协变 return 类型特征是派生的 class 为重写函数提供更多 specific/narrower return 类型。派生的 class return 类型被认为是协变的。
int* 不是 void* 类型,而像这样的东西确实描述了协变 return 类型:
struct Base {
virtual void *foo();
virtual Base* func();
};
struct Derived : Base {
// int *foo();
Derived* func(); //COVARIANT RETURN TYPE
};
void*
和 T*
之间的协方差是不允许的,因为:
1.缺乏一致性.
当前的协方差方式很容易理解,不会造成混淆。
试想 void*
类型的协方差是允许的。对于 1 阶段的推导很好,但它会造成混乱。例如:
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*
都不可能,为什么代码还在编译呢?查了最上面的classvoid_
才知道是因为double*
到void*
是"covariant"。编译器也一样:-)
2。引用问题
在 classes 的情况下,返回 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*`
这会造成混乱。