2010-05-13 14 views
18

In un progetto su cui sto lavorando, ho una classe Score, definita di seguito in score.h. Sto cercando di sovraccaricarlo così, quando viene eseguita un'operazione <<, viene stampato _points + " " + _name.Funzioni "amico" e << overloading dell'operatore: qual è il modo corretto di sovraccaricare un operatore per una classe?

Qui è quello che ho cercato di fare:

ostream & Score::operator<< (ostream & os, Score right) 
{ 
    os << right.getPoints() << " " << right.scoreGetName(); 
    return os; 
} 

Qui ci sono gli errori restituiti:

score.h(30) : error C2804: binary 'operator <<' has too many parameters 

(Questo errore compare 4 volte, in realtà)

sono riuscito a farlo funzionare dichiarando il sovraccarico come funzione amica:

friend ostream & operator<< (ostream & os, Score right); 

E rimuovere Score:: dalla dichiarazione della funzione in score.cpp (non dichiararlo efficacemente come membro).

Perché funziona, ma l'ex pezzo di codice non funziona?

Grazie per il vostro tempo!

EDIT

ho cancellato tutti i riferimenti al sovraccarico sul file di intestazione ... eppure ricevo il seguente (solo e) l'errore. binary '<<' : no operator found which takes a right-hand operand of type 'Score' (or there is no acceptable conversion) Come mai il mio test, in main(), non riesce a trovare il sovraccarico appropriato? (Non è la comprende, ho controllato)

Di seguito è la piena score.h

#ifndef SCORE_H_ 
#define SCORE_H_ 

#include <string> 
#include <iostream> 
#include <iostream> 

using std::string; 
using std::ostream; 

class Score 
{ 

public: 
    Score(string name); 
    Score(); 
    virtual ~Score(); 
    void addPoints(int n); 
    string scoreGetName() const; 
    int getPoints() const; 
    void scoreSetName(string name); 
    bool operator>(const Score right) const; 

private: 
    string _name; 
    int _points; 

}; 
#endif 

risposta

54

Nota: Si potrebbe desiderare di guardare il operator overloading FAQ.


Gli operatori binari possono essere membri della classe dell'argomento di sinistra o funzioni libere. (Alcuni operatori, come l'assegnazione, devono essere membri.) Poiché l'argomento di sinistra degli operatori dello stream è uno stream, gli operatori di flusso devono essere membri della classe stream o delle funzioni gratuite. Il modo canonico per implementare operator<< per qualsiasi tipo è questa:

std::ostream& operator<<(std::ostream& os, const T& obj) 
{ 
    // stream obj's data into os 
    return os; 
} 

Si noti che è non una funzione membro. Si noti inoltre che l'oggetto deve eseguire il flusso per riferimento a const. Questo perché non vuoi copiare l'oggetto per farlo streaming e non vuoi che lo streaming lo modifichi.


a volte si desidera per lo streaming di oggetti la cui struttura interna non sono accessibili attraverso la loro classe interfaccia pubblica, quindi l'operatore non può arrivare a loro.Allora si hanno due scelte: o mettere un membro pubblico nella classe che fa lo streaming

class T { 
    public: 
    void stream_to(std::ostream&) const {os << obj.data_;} 
    private: 
    int data_; 
}; 

e chiamare che da parte dell'operatore:

inline std::ostream& operator<<(std::ostream& os, const T& obj) 
{ 
    obj.stream_to(os); 
    return os; 
} 

o fare l'operatore di un friend

class T { 
    public: 
    friend std::ostream& operator<<(std::ostream&, const T&); 
    private: 
    int data_; 
}; 

in modo che possa accedere alla classe 'parti private:

inline std::ostream& operator<<(std::ostream& os, const T& obj) 
{ 
    os << obj.data_; 
    return os; 
} 
+0

Bella, risposta completa. –

+0

Accedi alle parti private della classe - Rawr. J/K, grazie mille, tuttavia rimane una domanda: Ho eliminato tutte le menzioni al sovraccarico sul file di intestazione ... tuttavia ottengo il seguente (e solo) errore. 'binario '<<': nessun operatore trovato che prende un operando di destra di tipo 'Punteggio' (o non vi è alcuna conversione accettabile)' Come mai il mio test, in main(), non riesce a trovare l'appropriato sovraccarico? (non è l'include). –

+1

Dovresti mettere la dichiarazione dell'operatore '' a destra con la definizione della tua classe: cioè nella stessa intestazione e nello stesso spazio dei nomi. In questo modo non ti dimenticherai di includerlo e il compilatore sarà in grado di prenderlo in cerca di sovraccarichi accettabili. –

9

Diciamo che si voleva scrivere un sovraccarico operatore per + così si potrebbe aggiungere due Score oggetti gli uni agli altri, e un altro così si potrebbe aggiungere un int ad un Score, e un terzo così si potrebbe aggiungere un Score a un int . Quelle in cui un Score è il primo parametro possono essere funzioni membro di Score. Ma quello in cui un int è il primo parametro non può diventare funzioni membro di int, giusto? Per aiutarti, ti è permesso scriverle come funzioni gratuite. Questo è ciò che sta accadendo con questo operatore <<, non è possibile aggiungere una funzione membro a ostream così si scrive una funzione libera. Questo è ciò che significa quando togli la parte Score::.

Ora, perché deve essere un friend? Non è così. Stai solo chiamando metodi pubblici (getPoints e scoreGetName). Si vedono molti operatori amici perché a loro piace parlare direttamente con le variabili private. Da parte mia è giusto farlo, perché sono scritti e mantenuti dalla persona che mantiene la classe. Basta non far confondere l'amico con la parte funzione-funzione-vs-libera-funzione.

+0

Grazie per l'input extra! –

6

Stai diventando errori di compilazione quando operator<< è una funzione membro nell'esempio perché si sta creando un operator<< che prende un Score come primo parametro (l'oggetto del metodo chiamato), e poi dandogli un extra parametro alla fine.

Quando si chiama un operatore binario dichiarato come funzione membro, il lato sinistro dell'espressione è l'oggetto sul quale viene chiamato il metodo. per esempio. a + b potrebbe funziona così:

A a; 
B b 

a.operator+(b) 

E 'in genere preferibile utilizzare gli operatori binari terzi (e in alcuni casi - ad esempio operator<< per ostream è l'unico modo per farlo in quel caso, a + b potrebbe funzionare come. questo:

A a; 
B b 

operator+(a, b); 

Ecco un esempio completo che mostra entrambi i modi di farlo; main() sarà in uscita '55' tre volte:

#include <iostream> 

struct B 
{ 
    B(int b) : value(b) {} 
    int value; 
}; 


struct A 
{ 
    A(int a) : value(a) {} 
    int value; 

    int operator+(const B& b) 
    { 
     return this->value + b.value; 
    } 
}; 

int operator+(const A& a, const B& b) 
{ 
    return a.value + b.value; 
} 

int main(int argc, char** argv) 
{ 
    A a(22); 
    B b(33); 

    std::cout << a + b << std::endl; 
    std::cout << operator+(a, b) << std::endl; 
    std::cout << a.operator+(b) << std::endl; 

    return 0; 
} 
Problemi correlati