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

我今天去参加一个面试,得到了一个有趣的问题。

除了内存泄漏和不存在虚拟 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();
}
4863 次浏览

You cannot index like that. You have allocated an array of Rectangles and stored a pointer to the first in shapes. When you do shapes[1] you're dereferencing (shapes + 1). This will not give you a pointer to the next Rectangle, but a pointer to what would be the next Shape in a presumed array of Shape. Of course, this is undefined behaviour. In your case, you're being lucky and getting a crash.

Using a pointer to Rectangle makes the indexing work correctly.

int main()
{
Rectangle * shapes = new Rectangle[10];
for (int i = 0; i < 10; ++i) shapes[i].draw();
}

If you want to have different kinds of Shapes in the array and use them polymorphically you need an array of pointers to Shape.

When indexing a pointer, the compiler will add the appropriate amount based on the size of what's located inside the array. So say that sizeof(Shape) = 4 (as it has no member variables). But sizeof(Rectangle) = 12 (exact numbers are likely wrong).

So when you index starting at say... 0x0 for the first element, then when you try to access the 10th element you're trying to go to an invalid address or a location that's not the beginning of the object.

As Martinho Fernandes said, the indexing is wrong. If you wanted instead to store an array of Shapes, you would have to do so using an array of Shape *'s, like so:

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();
}

Note that you have to do an extra step of initializing the Rectangle, since initializing the array only sets up the pointers, and not the objects themselves.