[C++] Operator<< overloaden.

Pagina: 1
Acties:

  • irondog
  • Registratie: Januari 2001
  • Laatst online: 11-05-2025

irondog

alle dingen moeten onzin zijn

Topicstarter
Ik wil een klasse maken waarbij ik de << operator kan gebruiken om allerlei typen te kunnen weergeven. Ik wil hierbij gedrag dat extreem veel lijkt op:
code:
1
std::cout << "test" << std::endl;

std::cout << kan namelijk omgaan met veel verschillende types.

Nu werkt het onderstaande voorbeeld bij gebruik van een template.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <sstream>

using namespace std;


class GVD
{
private:
        void show(stringstream &al) { std::cout << al.str(); }
public:
        GVD() {}
        ~GVD() {}
        template<class T> GVD& operator<<(T x) { stringstream al; al << x; show(al); return *this;}

};

int main() {
        GVD gvd;
        gvd << "Test\n";

}


Dit werkt op zich prima. Maar waarom werkt dit niet:
code:
1
gvd << "Test" << std::endl;


Met andere woorden: Kan ik die << operator ooit zo definiëren dat gvd << std::endl wel werkt?

[P5B deluxe] [Core2Duo 6300] [2 X 1GB DDR2] [GF FX7300] [320 GB WD] [Gentoo] [VISTA]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Misschien een domme vraag, maar wat "werkt er niet"? Compiled het niet, doet het niet wat je verwacht, crashed het? Met welke fout meldingen? Ik heb niet zo'n zin om je code in te tikken om het zelf uit te zoeken :)

  • irondog
  • Registratie: Januari 2001
  • Laatst online: 11-05-2025

irondog

alle dingen moeten onzin zijn

Topicstarter
Dit werkt niet (compilet niet):
gvd << "Test" << std::endl;

Dit wel:
gvd << "Test" << "\n";

Misschien een heel onlogische kwestie hoor. Maar ik wil dat gvd net zo werkt als cout.

[P5B deluxe] [Core2Duo 6300] [2 X 1GB DDR2] [GF FX7300] [320 GB WD] [Gentoo] [VISTA]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:12

.oisyn

Moderator Devschuur®

Demotivational Speaker

Heb je al eens bekeken waarom een std::endl op een ostream wel werkt? En wat een std::endl eigenlijk is?

En waarom probeer je eigenlijk een nieuwe klasse met dezelfde functionaliteit te maken? Kun je niet gewoon beter een std::streambuf implementeren en die aan een standaard stream hangen?

[ Voor 69% gewijzigd door .oisyn op 30-03-2006 11:30 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • irondog
  • Registratie: Januari 2001
  • Laatst online: 11-05-2025

irondog

alle dingen moeten onzin zijn

Topicstarter
.oisyn schreef op donderdag 30 maart 2006 @ 11:28:
Heb je al eens bekeken waarom een std::endl op een ostream wel werkt?
Ik had aangenomen dat std::endl een of ander type is.
En wat een std::endl eigenlijk is?
Waarschijnlijk heel iets anders dan een type.
En waarom probeer je eigenlijk een nieuwe klasse met dezelfde functionaliteit te maken?
Dat wordt pas interessant als ik in de show() functie van die klasse iets interessants ga doen. Deze functie krijgt een stringstream en kan net zo makkelijk met cout weergegeven worden als in een GUI element gepropt worden.
Kun je niet gewoon beter een std::streambuf implementeren en die aan een standaard stream hangen?
Ik zal daar eens naar kijken. Bedankt voor de hulp zover.

[P5B deluxe] [Core2Duo 6300] [2 X 1GB DDR2] [GF FX7300] [320 GB WD] [Gentoo] [VISTA]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:12

.oisyn

Moderator Devschuur®

Demotivational Speaker

irondog schreef op donderdag 30 maart 2006 @ 11:44:
[...]
Ik had aangenomen dat std::endl een of ander type is.


[...]
Waarschijnlijk heel iets anders dan een type.
Klopt, het is een functie die een std::ostream& als parameter verwacht en deze ook weer returnt. Een std::ostream heeft een operator << voor een dergelijke functie, en in de implementatie van die operator wordt gewoon die functie aangeroepen. En hoe dingen als std::setw werken mag je helemaal zelf uitzoeken ;)
Dat wordt pas interessant als ik in de show() functie van die klasse iets interessants ga doen. Deze functie krijgt een stringstream en kan net zo makkelijk met cout weergegeven worden als in een GUI element gepropt worden.
Ik heb het ook niet over wat je doet ín de operator, maar wat je klasse zelf voorstelt. Een stream zelf doet bijvoorbeeld niets, maar een fstream schrijft naar een file, terwijl een sstream naar een string schrijft. Denk je dan dat je eigen stream from scratch moet implementeren als je iets anders wilt dan een van deze dingen? Natuurlijk niet, dat zou enorm onhandig zijn. Daarom bestaat er een std::streambuf interface, die functies heeft om char arrays in te lezen en uit te voeren (vergelijkbaar met jouw show functie), en intern door streams gebruikt wordt voor de daadwerkelijke in-/uitvoer. Dat is waar je in geïnteresseerd bent, en dus kun je beter van een streambuf extenden en de juiste functies implementeren, zodat je de << operators en het omzetten van typen naar strings door ostream af kunt laten handelen en je dus niet opnieuw het wiel uitvindt :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • irondog
  • Registratie: Januari 2001
  • Laatst online: 11-05-2025

irondog

alle dingen moeten onzin zijn

Topicstarter
.oisyn schreef op donderdag 30 maart 2006 @ 15:28:
Klopt, het is een functie die een std::ostream& als parameter verwacht en deze ook weer returnt.
De operator << wordt het liefst geimplementeerd als eentje die hetzelfde type teruggeeft als dat ie accepteert ja. Dat maakt het mogelijk om de operator te herhalen. Zoals in:
code:
1
cout << "a" << "b" << 123 << endl


Was me al duidelijk hoor.
Een std::ostream heeft een operator << voor een dergelijke functie, en in de implementatie van die operator wordt gewoon die functie aangeroepen.
Helemaal duidelijk.
En hoe dingen als std::setw werken mag je helemaal zelf uitzoeken ;)
Ok.
Ik heb het ook niet over wat je doet ín de operator, maar wat je klasse zelf voorstelt. Een stream zelf doet bijvoorbeeld niets, maar een fstream schrijft naar een file, terwijl een sstream naar een string schrijft. Denk je dan dat je eigen stream from scratch moet implementeren als je iets anders wilt dan een van deze dingen? Natuurlijk niet, dat zou enorm onhandig zijn.
Ik wilde alleen iets wat net zo werkt als cout met 1: dezelfde syntax en 2: hetzelfde gemak van acceptatie van verschillende typen. Dat heb ik nu 1: via operator overloading en 2: via een template.

Wat heb je aan die klasse? Ik kan nu alle couts domweg vervangen door GVD. Uiteraard kan ik net zo goed een template functie maken zonder operator overloading die hetzelfde doet en vervolgens alle std::cout.operator <<() calls kunnen vervangen door de werkdende equivalent.

Goed, het is en blijft in jouw ogen waarschijnlijk een onmogelijk rare vraag om met een std::endl om te willen kunnen gaan. Ik zal waarschijnlijk na het verder verdiepen in de stuff die streams heet, inzien dat het nergens op slaat.
Daarom bestaat er een std::streambuf interface, die functies heeft om char arrays in te lezen en uit te voeren (vergelijkbaar met jouw show functie), en intern door streams gebruikt wordt voor de daadwerkelijke in-/uitvoer. Dat is waar je in geïnteresseerd bent, en dus kun je beter van een streambuf extenden en de juiste functies implementeren, zodat je de << operators en het omzetten van typen naar strings door ostream af kunt laten handelen en je dus niet opnieuw het wiel uitvindt :)
Geweldig. Ik zou mijn klasse dus op een of andere manier af moeten kunnen leiden van een streambuf. Klinkt veel beter ja. Nogmaals bedankt.

[P5B deluxe] [Core2Duo 6300] [2 X 1GB DDR2] [GF FX7300] [320 GB WD] [Gentoo] [VISTA]


  • Lone Gunman
  • Registratie: Juni 1999
  • Niet online
Hoewel het zelf schrijven van een streambuf goed te doen is, zou je ook eens kunnen kijken naar boost iostreams. Met deze library wordt het heel erg makkelijk om eigen streams te maken. Heb dit zelf ooit ns gebruikt om blockende serieele communicatie te doen via een stream, wat vrij snel te implementeren was door een device implementatie te schrijven mbv deze library.

offtopic:
hoi gerte

[ Voor 3% gewijzigd door Lone Gunman op 30-03-2006 18:11 ]

Experience has taught me that interest begets expectation, and expectation begets disappointment, so the key to avoiding disappointment is to avoid interest.


  • irondog
  • Registratie: Januari 2001
  • Laatst online: 11-05-2025

irondog

alle dingen moeten onzin zijn

Topicstarter
Lone Gunman schreef op donderdag 30 maart 2006 @ 18:10:
Hoewel het zelf schrijven van een streambuf goed te doen is, zou je ook eens kunnen kijken naar boost iostreams. Met deze library wordt het heel erg makkelijk om eigen streams te maken. Heb dit zelf ooit ns gebruikt om blockende serieele communicatie te doen via een stream, wat vrij snel te implementeren was door een device implementatie te schrijven mbv deze library.

offtopic:
hoi gerte
Jo Dennis. Bedankt voor de tip. Boost is al meegelinkt in de betreffende applicatie, dus dit is misschien wel interessant.

[P5B deluxe] [Core2Duo 6300] [2 X 1GB DDR2] [GF FX7300] [320 GB WD] [Gentoo] [VISTA]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:12

.oisyn

Moderator Devschuur®

Demotivational Speaker

irondog schreef op donderdag 30 maart 2006 @ 17:05:
[...]
De operator << wordt het liefst geimplementeerd als eentje die hetzelfde type teruggeeft als dat ie accepteert ja. Dat maakt het mogelijk om de operator te herhalen. Zoals in:
code:
1
cout << "a" << "b" << 123 << endl


Was me al duidelijk hoor.
Ik geloof niet dat je begrijpt wat ik zeg. Ik zeg dat std::endl een functie is die een ostream& accepteert en deze weer teruggeeft:

C++:
1
2
3
4
5
6
std::ostream& endl(std::ostream & o)
{
    o << '\n';
    o.flush();
    return o;
}


En dat er op ostream een operator << is gedefinieerd die een dergelijke functie accepteert:
C++:
1
2
3
4
std::ostream & operator << (std::ostream & o, std::ostream & (*func) (std::ostream &))
{
    return func(o);
}


En dáárom kun je std::cout << std::endl doen, en zo kun je het dus zelf ook implementeren. :)
Wat heb je aan die klasse? Ik kan nu alle couts domweg vervangen door GVD.
Nou, dan kun je je eigen stream implementatie gebruiken overal waar je een normale stream kunt gebruiken. Dat kan met jouw klasse momenteel niet. Bovendien kun je je streambuf in std::cout hangen zodat alle calls naar std::cout automatisch door je eigen streambuf gaan. Dan hoef je dus niets meer te vervangen. De iostreams zijn niet voor niets zo ontworpen en dit is ook de gebruikelijke manier om dit te implementeren. Bovendien is het een stuk minder werk dan de kant die je zelf op wil slaan.

[ Voor 61% gewijzigd door .oisyn op 30-03-2006 21:28 . Reden: Laatste alinea sloeg nergens op, ik moet beter lezen. Heb 'm weer weggehaald, excuus als je het al gelezen had :) ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • irondog
  • Registratie: Januari 2001
  • Laatst online: 11-05-2025

irondog

alle dingen moeten onzin zijn

Topicstarter
.oisyn schreef op donderdag 30 maart 2006 @ 21:17:

Ik geloof niet dat je begrijpt wat ik zeg. Ik zeg dat std::endl een functie is die een ostream& accepteert en deze weer teruggeeft:

En dat er op ostream een operator << is gedefinieerd die een dergelijke functie accepteert:
[...]
En dáárom kun je std::cout << std::endl doen, en zo kun je het dus zelf ook implementeren. :)
Wow. Het kwartje valt nu pas inderdaad.
Nou, dan kun je je eigen stream implementatie gebruiken overal waar je een normale stream kunt gebruiken. Dat kan met jouw klasse momenteel niet.
Nee inderdaad. :)
Bovendien kun je je streambuf in std::cout hangen zodat alle calls naar std::cout automatisch door je eigen streambuf gaan. Dan hoef je dus niets meer te vervangen. De iostreams zijn niet voor niets zo ontworpen en dit is ook de gebruikelijke manier om dit te implementeren. Bovendien is het een stuk minder werk dan de kant die je zelf op wil slaan.
Je moet de weg wel weten om de kortste te kunnen kiezen. :)

[P5B deluxe] [Core2Duo 6300] [2 X 1GB DDR2] [GF FX7300] [320 GB WD] [Gentoo] [VISTA]

Pagina: 1