I went to a job interview today and was given this interesting question.
Besides the memory leak and the fact there is no virtual dtor, why does this code crash?
#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(); }
Explanation: A base class pointer can point to a derived class object, but we can only access base class member or virtual functions using the base class pointer because object slicing happens when a derived class object is assigned to a base class object.
// As base-class pointer cannot access the derived class variable.
A Base Class pointer can point to a derived class object.
In C++, Pointers are variables that hold addresses of other variables. Not only can a pointer store the address of a single variable, it can also store the address of cells of an array.
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 Shape
s in the array and use them polymorphically you need an array of pointers to Shape.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With