我今天去了一个面试,并得到了这个有趣的问题.
除了内存泄漏和事实上没有虚拟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个元素时,您将尝试转到无效地址或不是对象开头的位置.