继承 - 为什么这是非法的

Inheritance - why is this illegal?

本文关键字:非法 为什么 继承      更新时间:2023-10-16

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

是的,在您的示例中确实s1->duplicate()调用Box::duplicate,但是您如何期望编译器知道这一点?从您的具体示例中可以说它是"显而易见的",但是此语言功能的规范对于此类"明显"的情况也不例外。

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* 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;