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

Ton*_*ion 98 c++ pointers

我今天去了一个面试,并得到了这个有趣的问题.

除了内存泄漏和事实上没有虚拟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();
}
Run Code Online (Sandbox Code Playgroud)

R. *_*des 149

你不能那样索引.您已经分配了一个数组,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();
}
Run Code Online (Sandbox Code Playgroud)

如果你想Shape在数组中有不同种类的s并以多态方式使用它们,你需要一个指向 Shape 的指针数组.


Pat*_*llo 36

正如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();
}
Run Code Online (Sandbox Code Playgroud)

请注意,您必须执行额外的初始化Rectangle步骤,因为初始化数组只会设置指针,而不是对象本身.


Jon*_*erg 13

索引指针时,编译器将根据数组内部的大小添加适当的数量.所以说sizeof(Shape)= 4(因为它没有成员变量).但sizeof(Rectangle)= 12(确切的数字可能是错误的).

因此,当您从第一个元素的说法开始索引... 0x0时,那么当您尝试访问第10个元素时,您将尝试转到无效地址或不是对象开头的位置.

  • 作为一个非 C++ 专家,提及 SizeOf() 帮助我理解了 @R. 马蒂尼奥在回答中这样说道。 (2认同)