协变return类型和类型转换

Covariant return type and type conversion

s->duplicate() return 类型为 Box* 的对象,但我在使用 Box* 初始化它时遇到错误。看起来它正在转换回 Shape*。如果将协变 return 类型转换回基础 class 指针,那么它有什么意义?:

struct Shape
{
    virtual Shape* duplicate()
    {
        return new Shape;
    }
};

struct Box : Shape
{
    virtual Box* duplicate()
    {
        return new Box;
    }
};

int main()
{
    Shape* s = new Box;
    Box*   b = s->duplicate();
}

错误:

main.cpp:22:12: error: cannot initialize a variable of type 'Box *' with an rvalue of type 'Shape *'
    Box*   b = s->duplicate();
           ^   ~~~~~~~~~~~~~~
1 error generated.

重点不是这样做:

Box*   b = s->duplicate();

这显然行不通,因为 Shape::duplicate() returns 和 Shape*。相反,如果您直接在 Box 上调用 duplicate(),则要接受 Box*

Box* old = new Box;
Box* b = old->duplicate(); // OK! We know it's a Box

尽管 Box::duplicate 在运行时调用(通过虚拟分派),尽管 Box::duplicate 确实 覆盖 Shape::duplicate(协变),虽然 Box::duplicate return 一个 Box*,你仍然会得到一个 Shape*指针,因为你是通过Shape*指针调用duplicate(),而Shape*Shape::duplicate()的return类型,编译器只会看到你调用Shape::duplicate,不是 Box::duplicate.

C++ 不能动态地 select 类型,所以这是它能做的最好的。您的 Box* 正在从 Box::duplicate 中自动转换为 Shape*。正如巴里所说,"it still has to compile at compile time, and at compile time all we know is that it returns a Shape*".

然后,要再次将其变成 Box*,您需要显式转换它(使用 static_castdynamic_cast),因为不存在隐式向下转换。

[C++11: 10.3/7]: 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. [..]

[C++11: 10.3/8]: If the return type of D::f differs from the return type of B::f, the class type in the return type of D::f shall be complete at the point of declaration of D::f or shall be the class type D. When the overriding function is called as the final overrider of the overridden function, its result is converted to the type returned by the (statically chosen) overridden function (5.2.2). [..]

在标准文本中,有一个相关示例。