2011-10-07 20 views
8

Ho una classe base e quindi diverse classi derivate. Vorrei sovraccaricare l'operatore "< <" per queste classi derivate. Per gli operatori normali, cioè '+', le funzioni virtuali fanno il trucco. Quello che capisco essere la convenzione standard è dichiarareoverloading << operatori e classi ereditate

friend ostream& operator<<(ostream& out, MyClass& A); 

all'interno della mia classe e quindi definire la funzione dopo la classe. A priori penserei che aggiungere una virtual alla definizione di cui sopra lo farebbe funzionare, ma dopo un po 'di riflessione (ed errori dal mio compilatore) mi rendo conto che non ha molto senso.

Ho provato una virata diversa in un caso di test, in cui tutti i membri della classe sono pubblici. Per esempio:

class Foo{ 
//bla 
}; 

ostream& operator<<(ostream& out, Foo& foo){ 
    cout << "Foo" << endl; 
    return foo; 
} 

class Bar : public Foo{ 
//bla 
}; 

ostream& operator<<(ostream& out, Bar& bar){ 
    cout << "Bar" << endl; 
    return bar; 
} 

/////////////////////// 

Bar bar = Bar(); 
cout << bar << endl; // outputs 'Foo', not 'Bar' 

Quindi, in qualche modo, questo è "il polimorfismo gone bad" - l'operatore di classe di base < < che viene chiamato, piuttosto che l'operatore classe derivata. Nell'esempio sopra, come faccio a chiamare l'operatore corretto per la classe derivata? E più in generale, se la mia classe ha membri privati ​​che voglio proteggere, come posso correggere l'overloading dell'operatore durante l'utilizzo della parola chiave friend?

risposta

6

È possibile utilizzare una funzione di supporto virtuale. Ecco un esempio del tutto testato, quindi si scusa per eventuali errori di sintassi:

virtual ostream& Foo::print(ostream& out) const { 
    return out << "Foo"; 
} 

virtual ostream& Bar::print(ostream& out) const { 
    return out << "Bar"; 
} 

// If print is public, this doesn't need to be a friend. 
ostream& operator<<(ostream& out, const Foo& foo) { 
    return foo.print(out); 
} 

Edit: Ripulito per suggerimenti @Omnifarious.

+0

Funziona perfettamente. Grazie. – andyInCambridge

+0

Penso che questo abbia due difetti. Un difetto è un enorme difetto e l'altro è un difetto secondario. Enorme difetto prima ... non dovresti mai inserire invisibilmente "endl". 'endl' impone un flusso di flusso, che può essere un grosso problema di prestazioni in alcune circostanze. Usa ''\ n''. È garantito che sia altrettanto portabile (infatti, 'endl' è definito in termini di output' '\ n'', e non comporta un sovraccarico di colore.In secondo luogo, farei questo: 'return out <<" Foo \ n ";'. Si sente leggermente più pulito e concettualmente trasforma l'intera cosa in una lunga catena di operazioni << << – Omnifarious

+0

@Omnifarious Non metterei mai endl in un overload dell'operatore. il codice dell'OP –

2

Generalmente si crea un metodo polimorfico print nella classe base chiamato da una singola funzione di libero amico.

+0

Se la stampa è pubblica, possiamo abbandonare l'amico. –

+0

Buoni punti in tutto, grazie. – andyInCambridge

1

Con le corrette correzioni del codice, il codice funziona correttamente; niente da fare:

ostream& operator<<(ostream& out, Foo& foo) { 
    out << "Foo" << endl; // 'out' and not 'cout' 
    return out; // returns 'out' and not 'foo' 
} 

ostream& operator<<(ostream& out, Bar& bar) { 
    out << "Bar" << endl; // 'out' and not 'cout' 
    return out; // returns 'out' and not 'bar' 
} 

Demo. Per accedere ai membri private, è possibile effettuare questa funzione come friend nello class desiderato.

+1

Intrigante. Nel mio codice in realtà avevo usato correttamente invece di cout, ma non funzionava ancora. Deve esserci qualcosa di sottile che non viene catturato dalle classi filler // bla. – andyInCambridge

Problemi correlati