Se sovraccaricato come funzione membro, a << b
viene interpretato come a.operator<<(b)
, pertanto è necessario un solo parametro esplicito (con this
come parametro nascosto).
Poiché ciò richiede che il sovraccarico faccia parte della classe utilizzata come operando di sinistra, non è utile con le normali ostream
e così via. Richiederebbe che il sovraccarico faccia parte della classe ostream
, non parte della tua classe. Dato che non sei autorizzato a modificare ostream
, non puoi farlo. Ciò lascia solo il sovraccarico globale come alternativa.
V'è, tuttavia, un modello piuttosto diffuso in cui si sovraccaricare l'operatore a livello globale, ma hanno che chiamano una funzione membro:
class whatever {
// make this public, or the global overload a friend.
std::ostream &write(std::ostream &dest) const {
// write self to dest
}
};
std::ostream &operator<<(std::ostream &os, whatever const &w) {
return w.write(os);
}
Ciò è particolarmente utile quando/se si desidera un comportamento polimorfico. Non è possibile rendere l'operatore sovraccaricato polimorfico stesso, ma si effettua la funzione membro che chiama virtual
, quindi agisce comunque polimorfico.
Modifica: per (spero) chiarire la situazione, è possibile farlo in modi diversi.Il primo e probabilmente il più ovvio è semplicemente rendere pubblico il nostro membro write
e farlo chiamare dall'operatore globale. Dal momento che è pubblico, non abbiamo a che fare nulla di speciale per lasciare che l'operatore usa:
class myClass {
public:
std::ostream &write(std::ostream &os) const {
// write stuff to stream
return os;
}
};
std::ostream &operator<<(std::ostream &os, myClas const &m) {
// since `write` is public, we can call it without any problem.
return m.write(os);
}
Una seconda alternativa è quella di rendere write
privato, e dichiarare operator<<
un amico per dargli l'accesso:
class myClass {
// Note this is private:
std::ostream &write(std::ostream &os) const {
// write stuff to stream
return os;
}
// since `write` is private, we declare `operator<<` a friend to give it access:
friend std::ostream &operator<<(std::ostream &, myClass const &);
};
std::ostream &operator<<(std::ostream &os, myClas const &m) {
return m.write(os);
}
C'è una terza possibilità che è quasi come il secondo:
class myClass {
// Note this is private:
std::ostream &write(std::ostream &os) const {
// write stuff to stream
return os;
}
// since `write` is private, we declare `operator<<` a friend to give it access.
// We also implement it right here inside the class definition though:
friend std::ostream &operator<<(std::ostream &os, myClas const &m) {
return m.write(os);
}
};
Questo terzo caso usa un po 'strano (e poco conosciuto) regola in C + + chiamato "nome iniezione". Il compilatore sa che una funzione friend
non può far parte della classe, quindi, invece di definire una funzione membro, questo "inietta" il nome di tale funzione nell'ambito circostante (l'ambito globale, in questo caso). Anche se operator<<
è definito all'interno della definizione di classe, è non una funzione membro a tutti - è una funzione globale.
Cosa succede se l'operatore << 'è dichiarato pubblico nella classe ma non implementato nella classe come' MyClass :: operator << '? È richiesto 'amico'? –
Interessante. Quindi può essere dichiarato nella classe, implementato come funzione non membro e non essere amico della classe per chiamare ancora le funzioni membro pubbliche di quella classe. –
@ 0A0D: Non sono sicuro di seguirlo. Nel mio precedente commento, "it" si riferiva alla funzione membro. Stai parlando di qualcos'altro? –