2010-09-03 31 views
15

Stavo guardando attraverso l'origine di OpenDE e mi sono imbattuto in un uso di sintassi strana dell'operatore di indicizzazione dell'array '[]' su una classe. Ecco un esempio semplificato per mostrare la sintassi:Che cosa significa questa sintassi C++ e perché funziona?

#include <iostream> 

class Point 
{ 
public: 
    Point() : x(2.8), y(4.2), z(9.5) {} 

    operator const float *() const 
    { 
     return &x; 
    } 

private: 
    float x, y, z; 
}; 

int main() 
{ 
    Point p; 
    std::cout << "x: " << p[0] << '\n' 
       << "y: " << p[1] << '\n' 
       << "z: " << p[2]; 
} 

uscita:

x: 2.8 
y: 4.2 
z: 9.5 

Che cosa sta succedendo qui? Perché questa sintassi funziona? La classe Point non contiene sovraccarico operator [] e qui questo codice sta provando a fare una conversione automatica per fluttuare da qualche parte.

Non ho mai visto questo tipo di utilizzo prima - sembra decisamente insolito e sorprendente a dir poco.

Grazie

+4

Nota che per scoprire se sta usando 'operator []' o una funzione di conversione puntatore puoi fare questo strano test: Se '0 [p]' funziona, sta usando una conversione puntatore. Se non funziona, ma se 'p [0]' funziona, sta usando 'operator []'. –

risposta

17

p viene convertito implicitamente in un const float* const, che indica x. Quindi *p è x, *(p+1) è e così via. È un'idea piuttosto bizzarra (e confusa!) Farlo in questo modo, ovviamente. Di solito è preferibile memorizzare x, yez in un array e avere una funzione per ottenere l'intero array se vogliono davvero fare le cose in questo modo.

+19

Senza contare che questo è completamente pericoloso poiché la posizione in memoria di 'x',' y' e 'z' non è ben definita. –

+0

ahhh okie grazie. È un codice intelligente là ... forse troppo intelligente: o – greatwolf

+2

@ D.Shawley: un buon punto. Mentre un compilatore "ragionevole" probabilmente farebbe questo, non credo che ci sia alcuna garanzia che questo layout sia standard. – rlbond

1

Questo è solo un modo di trattare i dati dei membri come una matrice. Puoi farlo anche con le strutture. Ciò è utile quando si desidera la leggibilità, ma si vuole essere in grado di scorrere su semplici strutture di dati. Un esempio di utilizzo potrebbe essere quello di dichiarare una matrice in questo modo:

typedef struct { 
    CGFloat m11,m12,m13,m14; 
    CGFloat m21,m22,m23,m24; 
    CGFloat m31,m32,m33,m34; 
    CGFloat m41,m42,m43,m44; 
} CATransform3D; 

Si può comodamente fare riferimento ogni cella per nome, ma si può anche passare intorno ad un puntatore a m11 in tutto il mondo (e C vedrà il vostro struct come un array, m11 è il primo elemento) e itera su tutti gli elementi.

8

L'idea è quella di consentire l'accesso ai membri del punto tramite pedice o nome. Se si vuole fare questo, però, si sarebbe meglio sovraccarico operator[] qualcosa di simile:

struct Point { 
    float x, y, z; 

    float &operator[](size_t subscript) { 
     switch(subscript) { 
      case 0: return x; 
      case 1: return y; 
      case 2: return z; 
      default: throw std::range_error("bad subscript"); 
     } 
    } 
}; 

In questo modo, se il compilatore inserisce imbottitura tra i carri, che continuerà a funzionare - e chiunque può leggere C++ dovrebbe essere in grado di capirlo senza problemi.

+1

Buon punto. Questo è quello che sto pensando anche io. So che quando stavo esaminando la fonte, non era ovvio cosa stesse facendo il codice. Penso che questo rientri sicuramente nel "codice troppo intelligente per il suo bene". : P – greatwolf

+0

+1 per il codice 'corretto' - sicuro, gestisce gli errori, leggibile, ecc. – JBRWilkinson

Problemi correlati