2009-09-05 16 views
28

Per favore aiutami a capire come funzionano esattamente gli operatori di conversione in C++. Qui ho un semplice esempio che sto cercando di capire, anche se non è molto chiaro come la conversione avvenga effettivamente dal compilatore.Operatori di conversione in C++

class Example{ 
public: 
    Example(); 
    Example(int val); 
    operator unsigned int(); 
    ~Example(){} 
private: 
    int itsVal; 
}; 

Example::Example():itsVal(0){} 

Example::Example(int val):itsVal(val){} 

Example::operator unsigned int(){ 
    return (itsVal); 
} 

int main(){ 
    int theInt = 5; 
    Example exObject = theInt; // here 
    Example ctr(5); 
    int theInt1 = ctr; // here 
    return 0; 
} 
+16

@Zuzu: Ho notato che hai 'utilizzando namespace std;' vicino alla parte superiore del file. Immagino che il tuo docente o materiale didattico lo abbia in questo modo. In questo esempio non ne hai bisogno, ma fai attenzione a dove lo usi. ** Mai ** mai usarlo in un file di intestazione - può causare un dolore indicibile se si desidera utilizzare nomi che si trovano nello spazio dei nomi 'std'. Considera di non usarlo affatto, ma se sei come me potresti voler usarlo solo nei moduli (file .cpp) e dopo tutto # include, ma prima delle definizioni di funzioni e metodi. – quamrana

+0

Qual è la tua domanda? –

risposta

4
Example exObject = theInt; // implicitly created copy constructor takes place 
// object implicitly created from int and then copied 
// it is like 
Example exObject = Example(theInt); 
// so it uses sequence 
// Example(int) -> Example(const Example&) 
int theInt1 = ctr; // operator int() 

Se compilatore supporta la copia ottimizzazione costruttore e l'ottimizzazione valore di ritorno non si noterà

Example(const Example&) 

esecuzione, ma è possibile dichiarare costruttore di copia per essere privato di capire di cosa sto parlando di.

+2

Example (int) non è un costruttore di copie. –

+0

Esempio (int) non lo è, ma Esempio esempio = int è. Utilizza il costruttore di copie implicitamente creato, no? –

+3

Copia codice avrebbe preso [const] Esempio e come primo argomento. In questo caso il compilatore chiama implicitamente Example (int), che è un normale ctor con un argomento: http://codepad.org/cGZ6YgT2 –

9

È possibile esaminare tale codice con un debugger (e/o inserire un punto di interruzione su ciascuno dei propri costruttori e operatori) per vedere quali dei propri costruttori e operatori sono stati richiamati da quali linee.

Perché non li hai definiti esplicitamente, il compilatore ha anche creato un costruttore di copia nascosta/predefinito e un operatore di assegnazione per la tua classe. È possibile definirli esplicitamente (come segue) se si desidera utilizzare un debugger per vedere dove/quando vengono chiamati.

Example::Example(const Example& rhs) 
: itsVal(rhs.itsVal) 
{} 

Example& operator=(const Example& rhs) 
{ 
    if (this != &rhs) 
    { 
     this->itsVal = rhs.itsVal; 
    } 
    return *this; 
} 
+0

Sai come disattivare RVO? –

+0

Le seguenti due righe mi stanno uccidendo .. Esempio exObject = theInt; int theInt1 = ctr; È un costruttore di copia richiamato in questo programma e su quale operatore di assegnazione. Nessuno di loro sembra essere chiamato. – Zuzu

2
Example exObject = theInt; // here 

Questo utilizza conversione implicita int all'Esempio, effettuato dal costruttore non esplicita che accetta un int.

Ciò richiede anche la disponibilità del costruttore di copie per Esempio, anche se al compilatore è consentito omettere di copiare l'istanza.

int theInt1 = ctr; // here 

Questo utilizza la conversione implicita di Esempio a int unsigned, fornita dall'operatore di trasmissione.

Gli operatori di cast sono normalmente evitati, in quanto tendono a generare codice confuso ed è possibile contrassegnare esplicitamente i costruttori a argomento singolo, per disabilitare le conversioni implicite nel tipo di classe. C++ 0x dovrebbe aggiungere anche la possibilità di contrassegnare esplicitamente gli operatori di conversione (quindi è necessario un static_cast per invocarli? - il mio compilatore non li supporta e tutte le risorse web sembrano concentrarsi sulla conversione esplicita in bool).

5
int main() { 
    int theInt = 5; 

    /** 
    * Constructor "Example(int val)" in effect at the statement below. 
    * Same as "Example exObject(theInt);" or "Example exObject = Example(theInt);" 
    */ 
    Example exObject = theInt; // 1 

    Example ctr(5); 

    /** 
    * "operator unsigned int()" in effect at the statement below. 
    * What gets assigned is the value returned by "operator unsigned int()". 
    */ 
    int theInt1 = ctr; // 2 

    return 0; 
} 

Alla dichiarazione 1 viene chiamato il costruttore Example(int val). Dichiaralo come explicit Example(int val) e otterrai un errore in fase di compilazione, vale a dire non sarà consentita alcuna conversione implicita per questo costruttore.

Tutti i costruttori a singolo argomento sono chiamati implicitamente se il valore assegnato è del rispettivo tipo di argomento. Utilizzando la parola chiave explicit prima che i costruttori a singolo argomento disabilitino la chiamata del costruttore implicito e quindi la conversione implicita.

Se il costruttore è stato dichiarato esplicito, ovvero explicit Example(int val), si verificherà quanto segue per ciascuna istruzione.

Example exObject(theInt); // Compile time error. 
Example exObject = theInt; // Compile time error. 
Example exObject(Example(theInt)); // Okay! 
Example exObject = Example(theInt); // Okay! 

noti inoltre che in caso di chiamata al costruttore implicito e quindi conversione implicita il valore assegnato è un rvalue cioèun oggetto senza nome implicitamente creata usando un lvalue (theInt) che ci dice che in caso di conversione implicita del compilatore converte

Example exObject = theInt; 

a

Example exObject = Example(theInt); 

Così (in C++ 11) don' Prevedo che il costruttore lvalue sia chiamato vedendo che stai usando un lvalue, ovvero un valore con nome theInt per l'assegnazione. Ciò che viene chiamato è il costruttore rval poiché il valore assegnato è in realtà l'oggetto non nominato creato usando il valore l. Tuttavia, questo si applica se si hanno entrambe le versioni lvalue e rvalue del costruttore.

Alla richiesta 2 operator unsigned int() viene chiamato. Consideralo semplicemente come una normale chiamata di funzione con un nome strano e il fatto che possa essere chiamata automaticamente quando avviene una conversione implicita. Il valore restituito da quella funzione è il valore assegnato nell'espressione. E dal momento che nell'implementazione il valore restituito è un intero viene assegnato correttamente a int theInt1.

Per essere precisisovraccarico () operatore che è l'operatore di trasmissione. Nel tuo caso è sovraccarico per int quindi ogniqualvolta un oggetto della classe Example viene assegnato a un int il casting di tipo implicito da Example a int viene eseguito e quindi viene chiamato operator unsigned int(). Pertanto,

int theInt1 = ctr; 

è equivalente a

int theInt1 = (int)ctr; 
+1

Esempio exObject (theInt); anche se il costruttore è esplicito, non penso che dovrebbe essere un errore in fase di compilazione. L'inizializzazione diretta è consentita. – bornfree

+0

Questo è dispari: 'Esempio exObject (Esempio (theInt));'. Sei sicuro che sia giusto? Forse intendevi scrivere 'Example exObject ((Example) theInt);' – mathiasfk