2015-07-07 23 views
36

Quando ho eseguito il seguente programmaPerché la funzione << dell'operatore tra std :: ostream e char è una funzione non membro?

#include <iostream> 

int main() 
{ 
    char c = 'a'; 
    std::cout << c << std::endl; 
    std::cout.operator<<(c) << std::endl; 

    return 0; 
} 

ho preso l'uscita

a 
97 

Scavando ulteriormente a http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt, ho notato che std::ostream::operator<<() non hai un sovraccarico che ha char come il tipo di argomento. La funzione chiamata std::cout.operator<<(a) viene risolta in std::ostream::operator<<(int), che spiega l'output.

Io parto dal presupposto che la funzione operator<< tra il std::ostream e char è dichiarato altrove:

std::ostream& operator<<(std::ostream& out, char c); 

In caso contrario, std::cout << a risolverebbe a std::ostream::operator<<(int).

La mia domanda è perché è dichiarata/definita come una funzione non membro? Ci sono problemi noti che impediscono che funzioni come membro?

+1

Forse a causa del parametro del modello del tipo di carattere? Questa funzione può avere la stessa implementazione ("efficiente") per qualsiasi tipo di carattere usando 'widen' delle impostazioni locali. – dyp

+1

Argomento interessante. Potrebbe essere una ragione per cui [ciò che è stato discusso qui] (http://stackoverflow.com/questions/31230237/enforcing-unsigned-char-to-be-numerically-outputted-from-function-call) non funziona. –

+1

@ dyp, non sembra molto convincente. –

risposta

12

L'insieme di inseritrici per std::basic_ostream include specializzazioni parziali per l'inserimento char, signed char, unsigned char e tale in basic_ostream<char, ...> flussi. Tieni presente che queste specializzazioni sono rese disponibili solo per gli stream , non per gli stream o gli stream basic_ostream<wchar_t, ...> in base a qualsiasi altro tipo di carattere.

Se si spostano questi modelli indipendenti nella definizione principale basic_ostream, diventeranno disponibili per tutti i moduli di specializzazione di basic_ostream. Apparentemente, gli autori delle biblioteche volevano impedire che ciò accadesse.

Io in realtà non so perché hanno voluto introdurre queste specializzazioni in cima al più generico

template<class charT, class traits> 
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, 
             char); 

di inserimento, ma a quanto pare hanno avuto il loro ragioni (ottimizzazione?).

La stessa situazione esiste per gli inseritori C-string. Oltre al inseritore più generico

template<class charT, class traits> 
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, 
             const char*); 

della specifica biblioteca dichiara anche più specifiche

template<class traits> 
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, 
             const char*); 

e così via.

+2

Non sono sicuro di comprendere appieno la tua risposta: esiste un generico 'template basic_ostream & operator << (basic_ostream & out, char c); 'modello di funzione che funziona bene per' wchar_t'. – dyp

+1

@ dyp: Sì, ma allo stesso tempo hanno sentito la necessità di introdurre la specializzazione dedicata per l'inserimento dei valori di 'char' in' char' stream. Non so davvero perché, ma le specifiche della biblioteca dicono che tale specializzazione esiste. – AnT

+0

Non sono del tutto sicuro che quella "specializzazione" impedisca un problema di risoluzione di sovraccarico. – dyp

4

Un motivo sta seguendo il consiglio generale di C++ di preferire funzioni non associate non membri alle funzioni membro. Questo è l'articolo 23 di Scott Meyer Effective C++. Questo è discusso in stackoverflow.

+2

Buono a dirlo. Questa regola empirica non sembra essere conosciuta da molti programmatori, portando ad antipodi di dio oggetto o oggetto orgia ... – JHBonarius

+0

Giusto, di solito ci penso in termini di accoppiamento o di evitare che tutto ciò che si potrebbe fare con alcuni classe diventando eccessivamente accoppiata. Preferirei i miglioramenti tramite l'interfaccia pubblica, quindi non mi devo preoccupare di come una tale funzione possa potenzialmente modificare lo stato dell'oggetto (influendo sugli invarianti di classe), anche se anche il membro 'const' può essere d'aiuto. Ciò facilita anche la partizione delle funzioni in vari file di intestazioni più focalizzati. –

Problemi correlati