我正在进行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;
}
答案 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
的指针,但y
是Box
,因为解析是:
Box (*x), y;