2012-08-15 92 views
8

我正在通过C++测验。并且遇到以下代码 - 这是违法的,但我不明白为什么。任何人都可以解释为什么这行:继承 - 为什么这是非法的?

Box* b1 = s1->duplicate(); 

生成编译器错误,“不能从Shape *转换为Box”? 我认为s1->duplicate()呼叫Box::duplicate(),因为s1实际上指向Box - 但从编译器错误它看起来像它叫Shape::duplicate()

#include <iostream> 

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

    virtual ~Shape() {} 
}; 

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

}; 

int main(int argc, char** argv) 
{ 
    Shape* s1 = new Box; 

    Box* b1 = s1->duplicate(); 

    delete s1; 
    delete b1; 
    return 0; 
} 
+1

由于[吨的他(http://stackoverflow.com/questions/4665117/c-virtual-function-return-type)。 – 2012-08-15 21:21:01

回答

8

Shape::duplicates()返回Shape*,这不是Box*。您实际返回的运行时类型与它无关。编译器如何知道返回的Shape*实际上指向Box

编辑:想想这个:

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

    virtual ~Shape() {} 
}; 

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

}; 

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

}; 

Shape* giveMeABoxOrASpehere() 
{ 
    if (rand() % 2) 
     return new Box; 
    else 
     return new Sphere; 
} 

// 
Shape* shape = giveMeABoxOrASphere(); 
// What does shape->duplicate() return? 

Box* shape = giveMeABoxOrASphere(); 
// shoud this compile? 
+0

嗯。好吧 - 我想我正在想,如果编译器可以接受'Shape * s' = new Box',那么它会知道* s1'现在是一个指向Box的指针。现在已经很晚了,我认为我的大脑被炸了。 。 。 – BeeBand 2012-08-15 21:21:35

+2

@BeeBand:'Shape * s = new Box;'和'Box * b = new Shape;'之间有一个重要的区别。 – aschepler 2012-08-15 21:36:33

+1

@BeeBand在这种情况下,您可以通过'dynamic_cast'找到,因此类型信息不会完全丢失。它只对编译器不可用。 – 2012-08-15 21:38:12

15

C++语言是静态类型的。您的电话合法性的决定是在编译时做出的。显然,编译器不知道s1->duplicate()返回指向Box对象的指针。在这种情况下,期待它接受你的代码是不合逻辑的。

是的,s1->duplicate()的确在您的例子中调用Box::duplicate,但您如何期望编译器知道这一点?可以说,从你的具体例子来看它是“显而易见的”,但是这种语言特征的规范对于这种“明显”的例子也不例外。

1

对于完全相同的原因

Shape* s1 = new Box; 
Box* b1 = s1; 

不能编译。编译器不在意s1是指Box,它也不应该在意。

如果你知道s1Box,只是说:

Box *s1 = new Box; 

有关语法的说明:用于Box * s1;解析规则(很简单):

declaration := type-name declarator ; 
declarator := name 
      | * declarator 

所以解析是:

Box  *  s1  ; 
        ^^^^^^^^ 
        declarator 
^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ 
type-name   declarator 

和分组是Box (* (s1))

它被认为是写Box *s1;,因为它是如果你在一个声明中声明超过一个变量的分析比Box* s1;更一致的最佳风格,Box*语法可能会造成混淆:

Box* x, y; 

x是一个指针Box,但yBox,作为解析是:

Box (*x), y; 
+0

ok,这要感谢提示。解析。 。 。 – BeeBand 2012-08-16 08:43:25

相关问题