协变返回类型和类型转换

时间:2015-01-25 03:20:50

标签: c++ covariance dynamic-dispatch

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

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.

2 个答案:

答案 0 :(得分:9)

虽然Box::duplicate 在运行时调用(通过虚拟调度),虽然Box::duplicate 覆盖Shape::duplicate(同上) ),虽然Box::duplicate 确实返回Box*,但您仍然会获得Shape*指针,因为您正在通过duplicate()调用Shape* Shape*指针,Shape::duplicate()Shape::duplicate的返回类型,编译器只会看到您调用Box::duplicate,而不是Box*

C ++无法动态选择类型,所以这是它能做的最好的。在Shape*的路上,您的Box::duplicate会自动转换为Shape*。正如Barry所说,"它仍然需要在编译时进行编译,在编译时我们所知道的是它返回Box*"。

然后,要再次将其设为static_cast,您需要明确地投射它(使用dynamic_cast[C++11: 10.3/7]:),因为不存在隐式下转换。

  

[C++11: 10.3/8]: 重写函数的返回类型要么与被覆盖函数的返回类型相同,要么与函数类的协变相同。 [..]

     

D::f如果B::f的返回类型与D::f的返回类型不同,则返回类型D::f中的类类型应为   在声明D时完成,或者是$(document).ready(function() { $('body').on('mouseover', 'li', function() { $("#vid").hide(); }); }); 类。 当覆盖函数被调用为被覆盖函数的最终覆盖时,其结果将转换为(静态选择的)覆盖函数(5.2.2)返回的类型。 [..]

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

答案 1 :(得分:5)

关键是不要这样做:

Box*   b = s->duplicate();

由于Shape::duplicate()返回Shape*,显然无效。相反,如果您直接在Box*致电duplicate(),则接受Box

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