指向基点的指针可以指向派生对象的数组吗?
Posted
技术标签:
【中文标题】指向基点的指针可以指向派生对象的数组吗?【英文标题】:Can a pointer to base point to an array of derived objects? 【发布时间】:2011-08-25 19:36:15 【问题描述】:我今天去面试,被问到这个有趣的问题。
除了内存泄漏和没有虚拟dtor,为什么这段代码会崩溃?
#include <iostream>
//besides the obvious mem leak, why does this code crash?
class Shape
public:
virtual void draw() const = 0;
;
class Circle : public Shape
public:
virtual void draw() const
int radius;
;
class Rectangle : public Shape
public:
virtual void draw() const
int height;
int width;
;
int main()
Shape * shapes = new Rectangle[10];
for (int i = 0; i < 10; ++i)
shapes[i].draw();
【问题讨论】:
除了缺少的分号,你是说? (不过,这将是编译时错误,而不是运行时错误) 你确定它们都是虚拟的吗? 应该是Shape **
指向一个矩形数组。那么访问应该是shapes[i]->draw();
@Tony 祝你好运,随时通知我们:)
@AndreyT:代码现在是正确的(最初也是正确的)。 ->
是编辑犯的错误。
【参考方案1】:
你不能这样索引。您已经分配了一个Rectangles
的数组,并在shapes
中存储了一个指向第一个数组的指针。当您执行shapes[1]
时,您将取消对(shapes + 1)
的引用。这不会给你一个指向下一个Rectangle
的指针,而是一个指向Shape
假定数组中的下一个Shape
的指针。当然,这是未定义的行为。在你的情况下,你很幸运并且遇到了崩溃。
使用指向Rectangle
的指针可使索引正常工作。
int main()
Rectangle * shapes = new Rectangle[10];
for (int i = 0; i < 10; ++i) shapes[i].draw();
如果您想在数组中包含不同类型的 Shape
s 并以多态方式使用它们,您需要一个指向 Shape 的 指针 数组。
【讨论】:
【参考方案2】:正如 Martinho Fernandes 所说,索引是错误的。如果您想存储 Shapes 数组,则必须使用 Shape * 数组,如下所示:
int main()
Shape ** shapes = new Shape*[10];
for (int i = 0; i < 10; ++i) shapes[i] = new Rectangle;
for (int i = 0; i < 10; ++i) shapes[i]->draw();
请注意,您必须执行一个额外的步骤来初始化 Rectangle,因为初始化数组只会设置指针,而不是对象本身。
【讨论】:
【参考方案3】:当索引一个指针时,编译器将根据数组内的大小添加适当的数量。所以说 sizeof(Shape) = 4 (因为它没有成员变量)。但是 sizeof(Rectangle) = 12(确切的数字可能是错误的)。
因此,当您从 0x0 开始索引第一个元素时,当您尝试访问第 10 个元素时,您会尝试转到无效地址或不是对象开头的位置。
【讨论】:
作为一个非 c++ 行家,提到 SizeOf() 帮助我理解了 @R。马蒂尼奥在他的回答中说。以上是关于指向基点的指针可以指向派生对象的数组吗?的主要内容,如果未能解决你的问题,请参考以下文章
如果继承类型受到保护,我可以使基类的指针指向派生对象吗? [复制]