Czy wskaźnik do bazy może wskazywać tablicę obiektów pochodnych?

Poszedłem dziś na rozmowę o pracę i dostałem to ciekawe pytanie.

Poza wyciekiem pamięci i faktem, że nie ma Wirtualnego dtor, dlaczego ten kod się zawiesza?

#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();
}
Author: Luc Danton, 2011-08-25

3 answers

Nie możesz tak indeksować. Przydzielono tablicę Rectangles i zapisano wskaźnik do pierwszej w shapes. Kiedy robisz {[3] }jesteś dereferencing (shapes + 1). Nie daje to wskaźnika do następnego Rectangle, ale wskaźnik do następnego Shape w domniemanej tablicy Shape. Oczywiście jest to nieokreślone zachowanie. W Twoim przypadku, masz szczęście i masz wypadek.

Użycie wskaźnika do Rectangle sprawia, że indeksowanie działa poprawnie.

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

Jeśli chcesz mieć różne rodzaje Shapes w tablicy i używać ich polimorficznie potrzebujesz tablicy wskaźniki kształt.

 149
Author: R. Martinho Fernandes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-25 22:49:37

Jak powiedział Martinho Fernandes, indeksowanie jest złe. Jeśli zamiast tego chcesz przechowywać tablicę kształtów, musisz to zrobić za pomocą tablicy kształtów * ' s, jak tak:

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

Zauważ, że musisz wykonać dodatkowy krok inicjalizacji prostokąta, ponieważ inicjalizacja tablicy ustawia tylko wskaźniki, a nie same obiekty.

 36
Author: Patrick Costello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-30 23:08:15

Podczas indeksowania wskaźnika kompilator doda odpowiednią ilość na podstawie rozmiaru tego, co znajduje się wewnątrz tablicy. Więc powiedzmy, że sizeof (Shape) = 4 (ponieważ nie ma zmiennych członkowskich). Ale sizeof (prostokąt) = 12 (dokładne liczby są prawdopodobnie błędne).

Więc kiedy indeksujesz zaczynając od powiedzmy... 0x0 dla pierwszego elementu, następnie podczas próby uzyskania dostępu do 10. elementu próbujesz przejść do nieprawidłowego adresu lub lokalizacji, która nie jest początkiem obiektu.

 13
Author: Jonathan Sternberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-25 19:41:45