2009-10-24 7 views
5

In C++ è possibile definire operatori di conversione che non sono membri della classe? So come farlo per gli operatori regolari (come +), ma non per gli operatori di conversione.Operatori di conversione definiti dall'utente C++ senza classi?

Ecco il mio caso d'uso: lavoro con una libreria C che mi consegna uno PA_Unichar *, dove la libreria definisce PA_Unichar come int a 16 bit. In realtà è una stringa codificata in UTF-16. Voglio convertirlo in un codice std::string codificato in UTF-8. Ho tutto il codice di conversione pronto e di lavoro, e sto manca solo lo zucchero sintattico che mi avrebbe permesso di scrivere:

PA_Unichar *libOutput = theLibraryFunction(); 
std::string myString = libOutput; 

(di solito in una linea senza la variabile temp).

anche la pena notare:

  • so che std::string non definisce conversione implicita da char* e so perché. La stessa ragione potrebbe applicarsi qui, ma questo è oltre il punto.

  • Ho una ustring, sottoclasse di std::string che definisce l'operatore di conversione corretto da PA_Unichar*. Funziona, ma questo significa utilizzare le variabili ustring anziché std::string e che quindi richiede la conversione in std::string quando utilizzo quelle stringhe con altre librerie. Quindi questo non aiuta molto.

  • L'utilizzo di un operatore di assegnazione non funziona come deve essere essere membri della classe.

Quindi è possibile definire operatori di conversione implicita tra due tipi che non controlli (nel mio caso PA_Unichar* e std::string), che possono o non possono essere tipi di classe?

In caso contrario, quali potrebbero essere soluzioni alternative?

risposta

8

Cosa c'è di sbagliato in una funzione gratuita?

std::string convert(PA_Unichar *libOutput); 

std::string myString = convert(theLibraryFunction()); 

Modifica risposta al commento:

Come DrPizza says: Tutti gli altri sta cercando di tappare i buchi aperti dalle conversioni implicite attraverso la loro sostituzione con quelli conversione esplicita che voi chiamate "ingombro visivo".

Per quanto riguarda la stringa temporanea: basta attendere la prossima versione del compilatore. È probabile che venga fornito con riferimenti rvalue e la sua implementazione std::string implementerà la semantica del movimento su quella che elimina la copia. Devo ancora vedere un modo più economico per accelerare il codice piuttosto che semplicemente aggiornando a una nuova versione del compilatore.

+0

cosa c'è che non va? Non molto, ma ancora due cose: - l'ingombro visivo, quando si hanno centinaia di chiamate senza senso per convertire - questa soluzione implica l'uso di una stringa temporanea std :: string. Ciò significa che i dati vengono copiati due volte, sempre. Questo può o non può essere un problema, ma non è molto soddisfacente. –

+6

La maggior parte dei compilatori ottimizzerà la copia extra. – rlbond

+4

jdmuys> rlbond ha ragione, il RVO è comune e reale nella pratica. Si potrebbe bacchetta leggere che: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – Klaim

4

Non penso che sia possibile definire operatori di conversione "globali". Gli standard dicono che conversion functions sono special member functions. Vorrei propse il seguente se potessi considerare quanto segue zucchero sintassi:

struct mystring : public string 
{ 
    mystring(PA_Unichar * utf16_string) 
    { 
     // All string functionality is present in your mystring. 
     // All what you have to do is to write the conversion process. 
     string::operator=("Hello World!"); 
     string::push_back('!'); 
     // any string operation... 
    } 
}; 

essere consapevoli del fatto che il comportamento polimorfico di questa classe è rotto.Purché non ne crei un oggetto attraverso un puntatore del tipo string*, sei al sicuro! Quindi, questo codice è perfetto:

mystring str(....); 

Come detto prima, il seguente codice è rotto!

string* str = new mystring(....); 
.... 
delete str; // only deleting "string", but not "mystring" part of the object 
// std::string doesn't define virtual destructor 
5

Le conversioni implicite sono comunque il diavolo. Rendilo esplicito con una chiamata alla funzione di conversione.

+4

Beh, dipende. Ci sono situazioni reali in cui le conversioni implicite hanno senso. In genere li uso, ad esempio, per convertire un tipo in un altro che è, in termini semantici, un sottoinsieme dell'altro. Ad esempio, se hai una classe 'person' e una' employee', mi aspetterei che 'employee' si converta automaticamente in' person' ovunque sia previsto. (Ovviamente, convertire implicitamente il contrario sarebbe una cattiva idea, d'altra parte.) – Mephane

+1

Mi rendo conto che stavi solo proponendo un esempio ipotetico, ma un dipendente come sottoclasse di persona è un cattivo design e un aspetto da il mio. La sottoclasse viene utilizzata per una relazione is-a. Sembra che un dipendente sia una persona, ma in realtà è solo una parte dell'ambiguità della grammatica inglese. Un dipendente non è un tipo speciale di persona, ma è invece un ruolo che una persona può avere. In realtà è una relazione has-a. –

3

No, non è possibile. Quello che potresti fare come alternativa è creare un costruttore di conversioni nella classe di destinazione (non il tuo caso, dato che vuoi convertire in std :: string - a meno che tu non lo abbia derivato). Ma sono d'accordo con le altre risposte, penso che una conversione implicita non è raccomandata in questo caso, specialmente perché non stai convertendo da un oggetto ma da un puntatore. Meglio avere una funzione libera, il tuo codice sarà più facile da capire e il prossimo programmatore che erediterà il codice ti assicurerà sicuramente grazie.

Problemi correlati