2009-11-09 27 views

risposta

33

Un riferimento deve essere inizializzato per fare riferimento a qualcosa; non può fare riferimento a nulla, quindi non puoi costruire in modo predefinito una classe che ne contiene una (a meno che, come altri suggeriscono, tu definisca un valore "nullo" globale). Avrete bisogno di un costruttore che viene dato il Div per riferirsi a:

explicit A(Div &d) : divs(d) {} 

Se si vuole che sia in grado di essere "nullo", allora avete bisogno di un puntatore, non un riferimento.

+1

In genere non è vero che non è possibile costruire in modo predefinito una classe con un membro di riferimento. Ad esempio, il riferimento può essere associato a un oggetto dichiarato nello spazio dei nomi (oggetto "globale", in parole più semplici). – AnT

+1

Come indicato, è possibile eseguire un costruttore predefinito se si utilizza una variabile predefinita (come nell'esempio seguente). –

+2

Siete entrambi corretti. Tuttavia, sconsiglio di utilizzare un valore globale "nullo" - non può essere const, quindi il comportamento predefinito sarebbe utilizzare un oggetto globale che qualsiasi altra istanza della classe può modificare senza preavviso. –

8

Per uno, si puo' t avere un riferimento NULL. Come secondo, tutti i riferimenti variabili in una classe devono essere inizializzati in fase di costruzione.

+0

Come posso correggerlo? – aajkaltak

+0

@varun: è necessario inizializzare il riferimento a un'istanza oggetto valida al momento della costruzione (ad esempio nel costruttore). – jldupont

+1

@varun: nota che puoi usare un puntatore se questo ti semplifica la vita ... o il refactoring. – jldupont

5

In "inglese": un riferimento si riferisce a qualcosa. Non può riferirsi a nulla (null). Ecco perché i riferimenti sono più sicuri da usare quindi i puntatori.

+5

Non solo in inglese. Lo stesso è vero in C++. – jalf

+1

lol, intendevo "la regola del linguaggio C++ scritto in inglese comune" ;-) – Abel

12

div è un riferimento, non un puntatore. Non è possibile impostarlo su NULL, deve puntare a un oggetto reale di qualche tipo. La cosa migliore da fare qui è probabilmente definire un'istanza statica/globale di Div che si definisce arbitrariamente come "Null Div" (imposta il suo valore su qualcosa che è improbabile che tu abbia mai usato) e inizializza div a quello. Qualcosa del genere:

struct Div 
{ 
    int i; 
    int j; 
}; 

Div NULL_DIV = { INT_MAX, INT_MAX }; 

class A 
{ 
    public: 
      A(); 
      Div& divs; 
}; 


A::A() : divs(NULL_DIVS) 
{ 
} 

Oppure, in alternativa, basta fare div a un puntatore anziché a un riferimento.

* Notare che non è possibile utilizzare un riferimento const a meno che non si stacchi la costanza perché per impostazione predefinita il compilatore non consente di assegnare un riferimento cosnt a un riferimento non const.

+0

si sta inizializzando un riferimento non const con oggetto const. Compila? – Arkadiy

+0

Ah, buona presa, no. Aggiornerò la risposta –

3

I riferimenti devono fare riferimento a qualcosa. Non esiste un riferimento null nel linguaggio C++. Se il membro non può avere un valore, allora dovrebbe essere un puntatore o un boost::optional o un tipo simile.

Un riferimento deve essere inizializzato per fare riferimento a un oggetto valido.

3

Ricordare che una volta inizializzato un riferimento per indicare qualcosa, non è possibile modificarlo per indicare qualcos'altro. Se questo non è il comportamento desiderato, allora dovresti usare un puntatore o una copia dell'oggetto.

1

Come indicato in altri post, i riferimenti (Div &) non possono essere nulli. Quindi la modifica più semplice che puoi fare è fornire un riferimento nel costruttore e inizializzare il tuo membro di riferimento.In questo modo,

class A 
{ 
    public: 
      A(Div& inDivs); 
      Div& divs; 

}; 

public A::A(Div& inDivs) 
: divs(inDivs) 
{} 
3

Il messaggio compilatore è uno di quei messaggi che non hanno senso dal punto di vista linguistico, ma rivelano il funzionamento interno del compilatore, la sequenza in cui le sue opere logica interna.

Nel tuo caso si sta utilizzando un valore di rvalue (NULL) per inizializzare un riferimento. Quando tale inizializzazione è consentita, il valore rval viene convertito in un oggetto temporaneo a cui verrà associato il riferimento. Quindi, il compilatore l'ha capito subito e ti ha informato del fatto con un messaggio diagnostico.

In realtà però, il trucco del genere è consentito solo per i riferimenti const, quindi il codice è danneggiato, poiché il riferimento non è const nel nostro caso. Inoltre, un riferimento struct, come quello nel codice, non può essere inizializzato con il valore NULL (che ha un tipo integrale), quindi è rotto anche per quel motivo.

Il messaggio del compilatore è piuttosto fuorviante. Il testo del messaggio sembra implicare che è illegale inizializzare i riferimenti dei membri con oggetti temporanei. In effetti, questo è legale in C++ (una volta risolti i problemi precedenti), anche se non ha senso. Ma, credo, una volta che il codice mal formati è accompagnato da almeno qualche messaggio di errore, dovrebbe essere OK per tutti ...

2

Chiaro e semplice:

Un riferimento non può mai essere NULL.

1
class A 
{ 
    Div & ref(Div div) { return div; } 
    public: 
     A() : divs(ref(Div())) {}; 
     Div& divs; 
}; 
+0

Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo sul perché e/o su come risponde alla domanda migliorerebbe significativamente il suo valore a lungo termine. Per favore modifica la tua risposta per aggiungere qualche spiegazione. – gevorg

0

vorrei suggerire:

class A{ 
    std::deque<object*>& que = *(std::deque<object*> *)0; 
    // ... 
    // Of course `que` is to be assigned valid deque before using it - just like pointers... 
}; 
+1

Per favore aggiungi del testo con il tuo codice descrivendo il motivo per cui lo consiglieresti. La domanda ha già una risposta accettata, quindi una spiegazione del perché la tua risposta è valida/migliore sarebbe di grande aiuto. – Banana

+0

Mi dispiace di non aver capito perché devo spiegare il motivo dell'utilizzo di questa soluzione, tranne che dimostra che funziona. – Bretzelus

+0

Potrebbe funzionare in alcune implementazioni, ma non è conforme. Se si desidera un puntatore, basta usare un puntatore, invece di tali imbrogli che violano completamente l'intento dei riferimenti. –

Problemi correlati