【问题标题】:Inheritance - why is this illegal?继承 - 为什么这是非法的?
【发布时间】:2012-08-15 21:14:08
【问题描述】:

我正在参加一个 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; 
}

【问题讨论】:

标签: c++ inheritance types typechecking


【解决方案1】:

C++ 语言是静态类型的。关于调用合法性的决定是在编译时做出的。很明显,编译器无法知道s1-&gt;duplicate() 返回一个指向Box 对象的指针。在这种情况下,期望它接受您的代码是不合逻辑的。

是的,s1-&gt;duplicate() 在您的示例中确实调用了Box::duplicate,但是您希望编译器如何知道这一点?从您的具体示例中可以说它是“显而易见的”,但是这种语言功能的规范对这种“显而易见”的情况也不例外。

【讨论】:

    【解决方案2】:

    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?
    

    【讨论】:

    • 嗯。好吧 - 我想我是这样想的,如果编译器可以接受 Shape* s = new Box`,那么它会以某种方式知道 s1 现在是一个指向 Box 的指针。太晚了,我觉得我的大脑已经炸了。 . .
    • @BeeBand:Shape* s = new Box;Box* b = new Shape; 之间有一个重要区别。
    • @BeeBand 在这种情况下,您可以通过dynamic_cast 找到,因此类型信息不会完全丢失。它只是编译器无法使用。
    • @BeeBand "假设我是这样想的 (...)" 是的,编译器可以有一个推理引擎。就像人类可以做出推断一样。请以数学方式描述您期望编译器拥有的推理引擎(如果有良好的数学描述,实现肯定是微不足道的)。 ;)
    • @FailedDev "盒子是一个形状" 。 . .我同意你的观点,但我无法在精神上飞跃到“因此 s1->Duplicate() 必须调用 Shape::duplicate()”。我正在尝试 :-)
    【解决方案3】:

    出于完全相同的原因

    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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-17
      • 1970-01-01
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      • 2013-12-29
      相关资源
      最近更新 更多