为什么我不能有 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*`

这会造成混乱。