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; 
}
4

3 回答 3

15

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

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

于 2012-08-15T21:17:28.957 回答
8

Shape::duplicates()返回 a Shape*,它不是 a Box*。您实际返回的运行时类型与它无关。编译器怎么知道Shape*返回的实际上指向 a 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?
于 2012-08-15T21:17:53.010 回答
1

出于完全相同的原因

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

不编译。编译器不关心s1引用 a Box,也不应该关心。

如果您知道s1指的是 a 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,但是y是一个Box,因为解析是:

Box (*x), y;
于 2012-08-16T00:12:16.513 回答