2011-08-25 12 views
97

Oggi sono andato a un colloquio di lavoro e mi è stata data questa interessante domanda.Un puntatore può puntare il punto di base a una matrice di oggetti derivati?

Oltre alla perdita di memoria e al fatto che non esiste un operatore virtuale, perché questo codice si arresta?

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

Oltre al punto e virgola mancante, vuoi dire? (Sarebbe un errore in fase di compilazione, tuttavia, non in fase di esecuzione) –

+0

Sei sicuro che fossero tutti virtuali? –

+0

@Yochai, sì ne sono sicuro. –

risposta

148

Non è possibile indicizzare in questo modo. È stato assegnato un array di Rectangles e memorizzato un puntatore sul primo di shapes. Quando esegui il shapes[1] stai differenziando (shapes + 1). Questo non ti darà un puntatore al prossimo Rectangle, ma un puntatore a quello che sarebbe il prossimo Shape in una presunta matrice di Shape. Certo, questo è un comportamento indefinito. Nel tuo caso, sei stato fortunato e hai avuto un incidente.

L'utilizzo di un puntatore su Rectangle rende l'indicizzazione funzionante.

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

Se si desidera avere diversi tipi di Shape s nella matrice e li usa polimorfico è necessario un array di puntatori to Shape.

+0

Sì, questo è corretto. :) –

13

Durante l'indicizzazione di un puntatore, il compilatore aggiungerà l'importo appropriato in base alle dimensioni di ciò che si trova all'interno della matrice. Quindi dì che sizeof (Shape) = 4 (dato che non ha variabili membro). Ma sizeof (Rectangle) = 12 (i numeri esatti sono probabilmente sbagliati).

Quindi quando si indice partendo da say ... 0x0 per il primo elemento, quando si tenta di accedere al decimo elemento si sta tentando di accedere a un indirizzo non valido o a una posizione che non è l'inizio dell'oggetto.

+1

Come adept non C++, menzionare SizeOf() mi ha aiutato a capire cosa @R. Martinho stava dicendo nella sua risposta. –

36

Come ha detto Martinho Fernandes, l'indicizzazione è errata. Se si voleva, invece di memorizzare una serie di forme, si dovrebbe fare in modo da utilizzare una serie di Shape * s ', in questo modo:

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

Nota che devi fare un ulteriore passo di inizializzazione del rettangolo, poiché l'inizializzazione dell'array imposta solo i puntatori e non gli oggetti stessi.

Problemi correlati