指向基点的指针可以指向派生对象的数组吗?

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:代码现在是正确的(最初也是正确的)。 -&gt; 是编辑犯的错误。 【参考方案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();

如果您想在数组中包含不同类型的 Shapes 并以多态方式使用它们,您需要一个指向 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。马蒂尼奥在他的回答中说。

以上是关于指向基点的指针可以指向派生对象的数组吗?的主要内容,如果未能解决你的问题,请参考以下文章

如果继承类型受到保护,我可以使基类的指针指向派生对象吗? [复制]

使用具有指向派生类对象的指针的基类指针数组调用派生类方法

在 C++ 继承中,当指向基类的指针对象指向派生类时,不调用派生类析构函数

为啥我可以通过指向派生对象的基类指针访问派生私有成员函数?

基类指针指向派生类对象&派生类指针指向基类对象

指向包含可分配数组的派生类型的指针