继承 - 为什么这是非法的?

时间:2012-08-15 21:14:09

标签: c++ inheritance types typechecking

我正在进行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; 
}

3 个答案:

答案 0 :(得分:15)

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

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

答案 1 :(得分: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?

答案 2 :(得分:1)

出于同样的原因

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

无法编译。编译器并不关心s1是指Box,也不关心它。

如果您知道s1引用Box,请说出来:

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;