quando faccio questo (nella mia class)
public: Entity() { re_sprite_eyes = new sf::Sprite(); re_sprite_hair = new sf::Sprite(); re_sprite_body = new sf::Sprite(); } private: sf::Sprite* re_sprite_hair; sf::Sprite* re_sprite_body; sf::Sprite* re_sprite_eyes;
Tutto funziona bene Tuttavia, se cambio le dichiarazioni a questo:
private: sf::Sprite* re_sprite_hair, re_sprite_body, re_sprite_eyes;
Ottengo questo errore del compilatore:
error: no match for 'operator=' in '((Entity*)this)->Entity::re_sprite_eyes = (operator new(272u), (, ((sf::Sprite*))))
E poi dice che i candidati per re_sprite_eyes
sono oggetti sf::Sprite
e / o riferimenti.
Perché non funziona? Le dichiarazioni non sono le stesse?
sf::Sprite* re_sprite_hair, re_sprite_body, re_sprite_eyes;
Non dichiara 3 puntatori: è un puntatore e 2 oggetti.
sf::Sprite*
sfortunatamente non si applica a tutte le variabili dichiarate dopo, solo la prima. È equivalente a
sf::Sprite* re_sprite_hair; sf::Sprite re_sprite_body; sf::Sprite re_sprite_eyes;
Vuoi fare:
sf::Sprite *re_sprite_hair, *re_sprite_body, *re_sprite_eyes;
Devi mettere una stella per ogni variabile. In questi casi preferisco mantenere la stella sul lato della variabile, piuttosto che sul tipo, per chiarire esattamente questa situazione.
Sia in C che in C ++, il *
lega al dichiaratore , non allo specificatore del tipo. In entrambe le lingue, le dichiarazioni sono basate sui tipi di espressioni , non sugli oggetti.
Ad esempio, supponiamo di avere un puntatore a un int
chiamato p
e di accedere al valore int
cui punta p
; lo fai diterferendo il puntatore con l’operatore unario *
, in questo modo:
x = *p;
Il tipo dell’espressione *p
è int
; quindi, la dichiarazione di p
è
int *p;
Questo è vero indipendentemente dal numero di puntatori che dichiari all’interno della stessa dichiarazione; se anche q
e r
devono essere dichiarati come puntatori, allora devono anche avere l’unario *
come parte del dichiaratore:
int *p, *q, *r;
perché le espressioni *q
*r
hanno tipo int
. È un incidente di syntax C e C ++ che puoi scrivere T *p
, T* p
o T * p
; tutte queste dichiarazioni saranno interpretate come T (*p)
.
Questo è il motivo per cui non mi piace lo stile C ++ di dichiarare puntatori e tipi di riferimento come
T* p; T& r;
perché implica una visualizzazione errata di come funziona la syntax delle dichiarazioni C e C ++, portando al tipo esatto di confusione che hai appena sperimentato. Tuttavia, ho scritto abbastanza C ++ per capire che ci sono momentjs in cui quello stile rende l’intento del codice più chiaro, specialmente quando si definiscono i tipi di container.
Ma è ancora sbagliato.
In C ++ 11 hai una piccola soluzione, che potrebbe essere migliore di spostare gli spazi avanti e indietro:
template using type=T; template using func=T*; // I don't like this style, but type i, j; works ok type i = new int{3}, j = new int{4}; // But this one, imho, is much more readable than int(*f)(int, int) = ... func f = [](int x, int y){return x + y;}, g = [](int x, int y){return x - y;};
Un’altra cosa che potrebbe attirare la vostra attenzione è la linea:
int * p1, * p2;
Questo dichiara i due puntatori usati nell’esempio precedente. Ma si noti che c’è un asterisco (
*
) per ogni puntatore, in modo che entrambi abbiano il tipoint*
(puntatore a int). Questo è richiesto a causa delle regole di precedenza. Si noti che, se, invece, il codice era:int * p1, p2;
p1
sarebbe effettivamente di tipoint*
, map2
sarebbe di tipoint
. Gli spazi non hanno alcuna importanza per questo scopo. In ogni caso, ricordare semplicemente di mettere un asterisco per puntatore è sufficiente per la maggior parte degli utenti di puntatori interessati a dichiarare più puntatori per istruzione. O ancora meglio: usa un diverso statemet per ogni variabile.
L’asterisco si lega al nome della variabile del puntatore. Il modo per ricordare questo è notare che in C / C ++, le dichiarazioni imitano l’uso.
I puntatori potrebbero essere usati in questo modo:
sf::Sprite *re_sprite_body; // ... sf::Sprite sprite_bod = *re_sprite_body;
Allo stesso modo,
char *foo[3]; // ... char fooch = *foo[1];
In entrambi i casi, esiste un identificatore di tipo sottostante e l’operatore o gli operatori necessari per “ottenere” un object di quel tipo in un’espressione.