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

我今天去面试了,给了这个有趣的问题。

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

你不能像那样索引。 你已经分配了一个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并且使用它们,你需要一个指向 Shape的指针数组。

正如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的额外步骤,因为初始化数组只是设置指针,而不是对象本身。

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

所以,当你从第一个元素的0x0开始索引的时候,当你试图访问第10个元素时,你试图去找一个无效的地址或者一个不是该对象开始的位置。