Toon posts:

[C++] operator overloading

Pagina: 1
Acties:

Verwijderd

Topicstarter
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Nummer
{
private:
  int i;

public:
  Nummer () : i(0) { };
  Nummer (const int &I) : i(I) { };

  int operator=(const Nummer &n) { return n.i; };
};

void main ( void )
{
  Nummer i;
  Nummer j(20);

  int k(i); // error C2440: 'initializing' : cannot convert from 'class Nummer' to 'int'
}


Hoe moet ik nu die operator gaan overloaden zodat ik die Nummer kan gaan gebruiken als int?

[ Voor 7% gewijzigd door .oisyn op 19-02-2003 10:28 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 16:37
Operator overloading heeft hier afaik niets mee te zien.

Volgens mij ligt het hieraan:
Je wilt een primitieve variable van het type integer maken, en je wilt ze een waarde geven, nl. de waarde die in de variable Nummer::i zit. Maar, aangezien i een primitief is, kan i mi geen constructor hebben.

https://fgheysels.github.io/


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

je kunt casting operatoren ook overloaden (oftewel: je moet een operator int definieren)

overigens is het gebruikelijk om het returntype van de = operator een referentie van je type te laten zijn, dus:
C++:
1
Nummer & operator = (const Nummer & pNummer);

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.


Verwijderd

Topicstarter
Wat ik eigenlijk wil is:

C++:
1
2
3
4
Nummer nr; // dus nr::i = 0
int i_nr; // i_nr = onbepaald

i_nr = nr; // nu wil ik dat in i_nr de waarde van nr::i komt te staan (hier 0 dus)



Ik dacht dat dit mogelijk was met operator overloading? De gemakkelijke oplossing is natuurlijk een getter te maken iet lijk nr.GetInt() die dan "return i;" doet. Maar dat is niet echt wat ik wil.

Ik wil nr kunnen gebruiken als een integer.

Ik ben nu bezig op die class Nummer, maar ik ga dit uitbreiden naar char*. Maar int is simpeler om mee te werken, daarmee...

[ Voor 5% gewijzigd door Verwijderd op 19-02-2003 10:35 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Lees mijn post! je moet een casting operator overloaden

voorbeeldje dan maar:
C++:
1
2
3
4
operator int ()
{
    return i;
}


ps: gebruik [norml]
C++:
1
...
voor syntax highlighting[/]

[ Voor 22% gewijzigd door .oisyn op 19-02-2003 12:47 ]

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.


Verwijderd

Topicstarter
oh! zo simpel. En daar zit ik dan al 2 dagen op te zoeken :-)

argh :-)

ps: dank je, ik vroeg me al af hoe dat gedaan werd (omdat in faq werd gezegd [code] wist automatisch welke taal te kiezen)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Mag ik vragen waarom je dit niet gewoon by-value doet? :?

Professionele website nodig?


Verwijderd

Topicstarter
References werken rapper. Niet dat dat iets uitmaakt bij integers :)

Maar het is kwestie van gewoonte.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 19 February 2003 @ 10:53:
References werken rapper. Niet dat dat iets uitmaakt bij integers :)


het maakt wel uit: bij integers werkt het juist slomer (in theorie dan he ;)). Je geeft namelijk een pointer mee die dereferenced moet worden. Buiten dat, als je een int literal of een temporary (zoals het resultaat van een expressie) meegeeft moet er stackruimte worden aangemaakt om die int in te zetten, omdat er een adres nodig is

Imho worden references pas interessant als sizeof (T) > 8

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.


Verwijderd

Maar ff voor de duidelijkheid, wil je opnieuw je code ff posten?
plz _/-\o_

  • tomato
  • Registratie: November 1999
  • Niet online
Verwijderd schreef op 19 February 2003 @ 11:33:
Maar ff voor de duidelijkheid, wil je opnieuw je code ff posten?
plz _/-\o_
.oisyn op 19 February 2003 @ 10:33

Verwijderd

Topicstarter
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Nummer 
{ 
private: 
  int i; 

public: 
  Nummer () : i(0) { }; 
  Nummer (const int &I) : i(I) { }; 

  operator int() { return i; }; 
}; 

void main ( void ) 
{ 
  Nummer i; 
  Nummer j(20); 

  int k(i); // error == gone :)
}

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Verwijderd schreef op 19 februari 2003 @ 10:53:
References werken rapper. Niet dat dat iets uitmaakt bij integers :)

Maar het is kwestie van gewoonte.
Ik stel dat soort vragen niet uit stupiditeit (leer mij C++....) maar om je er even over na te laten denken. Op de 64-bit CPU's soon-to-come ga jij namelijk ipv 4 bytes welzeker 8 bytes doorsturen (leuk die pointers). Daarnaast is het afhankelijk van de compiler en situatie wellicht zoals D2k inderdaad langzamer: een reference houdt in dat je wellicht in de functie het adres van het origineel wil hebben en dus moet echt via een omweg (zijnde het adres) het ding aangesproken worden. Daarnaast laat een const-reference altijd de mogelijkheid open dat een implementatie een ranzige const_cast gaat gebruiken op het ding om 'm alsnog te wijzigen.

Oftewel hele slechte gewoonte: atomaire types doe je altijd by-value. Leer het je maar aan.

ps. vraagje: stuur je pointers ook altijd by-const-reference door? Zo nee ben je ook nog inconsequent tegen je eigen gewoonte.

Professionele website nodig?


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-08 16:32
whoami schreef op 19 February 2003 @ 10:24:
Operator overloading heeft hier afaik niets mee te zien.

Volgens mij ligt het hieraan:
Je wilt een primitieve variable van het type integer maken, en je wilt ze een waarde geven, nl. de waarde die in de variable Nummer::i zit. Maar, aangezien i een primitief is, kan i mi geen constructor hebben.
Hmm, geen echte constructor denk ik maar wel een (default) initialisatie:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class IntInit
{
public:
    int getVal(){ return 100;}
    operator int() { return 500;}
};

int main()
{
    IntInit init;
    
    int i( int( ) );
    int j;
    int k(init);
    int l(init.getVal());

    cout<<"i="<<i<<'\n';
    cout<<"j="<<j<<'\n';
    cout<<"k="<<k<<'\n';
    cout<<"l="<<l<<'\n';

    getchar();
    return 0;
}


geeft bij mij als output:

i=0
j=-858993460
k=500
l=100

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

Topicstarter
Waar ik meestal mee bezig zit zijn doorgeven van classes met een geheugengrootte van +-10 a 12KB. Ik heb liever niet dat die by value doorgegeven worden, anders lagged dat de hele server.

Wat ik gewoon wil bereiken is een adres doorgeven. Op deze manier is mij verteld (tenzij jij anders beweerd of course ;)) dat je enkel adres doorgeeft (dus 4 / 8 bytes). En dit is zeker sneller als 10 of 12Kb.

Wat bedoel je juist bij het 'aanspreken'? Bvb ik heb een CPlayer& pPlayer. Als ik dit wil aanspreken, dan (wat ik denk, corrigeer me indien ik fout zit) gaat die naar het adres van pPlayer kijken, dan bij dat geheugenadres de var/functie oproepen die ik nodig heb? Hoe zou ik het performanter kunnen doen?

Ivm die const-reference. Wat stel je dan zelf voor? Of hoe doe je het zelf? Als ik een const gebruik is dit met de bedoeling dat aan dat ding niets veranderd mag worden. (bvb bij "const int &I" mag I niet gewijzigd worden.

Dit was maar een test class hé :) Iets geschreven op 1 minuutje voor die "operator int" te kunnen zien hoe ik dat moest doen.

Ik probeer zoveel mogelijk const te gebruiken. Ik vind dit enorm handig want dan weet ik dadelijk wanneer ik ergens iets verander daar ik eigenlijk niet aan zou mogen komen.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

farlane schreef op 19 February 2003 @ 12:58:
[...]

Hmm, geen echte constructor denk ik maar wel een (default) initialisatie:
[...]
geeft bij mij als output:

i=0
j=-858993460
k=500
l=100


Ook primitieven hebben constructoren en destructoren. De destructor doet niets, maar je kunt ze wel expliciet aanroepen (wel via een typedef type overigens, anders krijg je parse errors). Ze hebben een default-constructor en een copy-constructor. De default-constructor initializeert ze op 0

Let wel dat, in tegenstelling tot classes, de default constructor niet wordt aangeroepen als je er geen haakjes bij zet:

C++:
1
2
3
4
5
int i1;     // blaat is niet geinitializeerd
int i2 ();   // i2 is 0

MijnKlasse k1;
MijnKlasse k2 ();   // deze 2 statements doen hetzelfde

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.


  • Eelis
  • Registratie: Januari 2003
  • Laatst online: 21-02-2015
.

[ Voor 99% gewijzigd door Eelis op 18-02-2015 19:45 ]


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
.oisyn schreef op 19 February 2003 @ 10:58:
het maakt wel uit: bij integers werkt het juist slomer (in theorie dan he ;)). Je geeft namelijk een pointer mee die dereferenced moet worden. Buiten dat, als je een int literal of een temporary (zoals het resultaat van een expressie) meegeeft moet er stackruimte worden aangemaakt om die int in te zetten, omdat er een adres nodig is

Imho worden references pas interessant als sizeof (T) > 8
Ook in praktijk, tenzij de compiler/linker slim genoeg is om toch by-value die param door te geven.
Eelis schreef op 19 February 2003 @ 13:30:
[...]

Neen. int i2 (); en MijnKlasse k2 (); zijn functiedeclaraties.
Inderdaad. int() is wel 0.

[ Voor 16% gewijzigd door Olaf van der Spek op 19-02-2003 13:32 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Eelis schreef op 19 February 2003 @ 13:30:
[...]

Neen. int i2 (); en MijnKlasse k2 (); zijn functiedeclaraties.


klopt idd, maar wat ik probeerde aan te geven was dat een expliciete default constructor nodig is voor initializatie bij primitieven, terwijl dat blij classes niet het geval is

ander, wel werkend voorbeeld:

C++:
1
2
3
4
5
6
7
8
9
struct Test
{
    int i1, i2;
    MijnKlasse k1, k2;

    Test () : i2 (), k2 ()
    {
    }
}


int::int () wordt niet aangeroepen bij i1, terwijl MijnKlasse::MijnKlasse () wel wordt aangeroepen bij k1

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.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker



door goed gebruik van pipelining hoeft het niet langzamer te zijn, ookal is het meer instructies

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.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
.oisyn schreef op 19 February 2003 @ 13:19:
Ook primitieven hebben constructoren en destructoren. De destructor doet niets, maar je kunt ze wel expliciet aanroepen (wel via een typedef type overigens, anders krijg je parse errors). Ze hebben een default-constructor en een copy-constructor. De default-constructor initializeert ze op 0

Let wel dat, in tegenstelling tot classes, de default constructor niet wordt aangeroepen als je er geen haakjes bij zet:

C++:
1
int i1;     // blaat is niet geinitializeerd
Hmm. Ik moet je helaas ongelijk geven; de builtins hebben geen (default) constructors. Je beschrijving van het gedrag klopt op zich wel. Het is bijvoorbeeld duidelijk uit het feit dat je die "int constructor" of "int destructor" niet een friend kunt laten zijn van een class. De syntax die jij beschrijft voor de "int destructor" heet dus ook een "pseudo-destructor-call"

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
.oisyn schreef op 19 February 2003 @ 13:41:
door goed gebruik van pipelining hoeft het niet langzamer te zijn, ookal is het meer instructies
Dat gaat lang niet altijd op, en bovendien leidt het zelfs met pipelining tot een grotere busbelasting. Dat is om een SMP/Hyperthreading machine kwalijk; zelfs als je de ene CPu niet vertraagd door de pipelining kan de ander langzamer worden.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Verwijderd schreef op 19 februari 2003 @ 13:07:
Waar ik meestal mee bezig zit zijn doorgeven van classes met een geheugengrootte van +-10 a 12KB. Ik heb liever niet dat die by value doorgegeven worden, anders lagged dat de hele server.
Bliep klasses van 10-12Kb? Ik mag toch hopen dat dat incluis indirect gealloceerd geheugen is?
Wat ik gewoon wil bereiken is een adres doorgeven. Op deze manier is mij verteld (tenzij jij anders beweerd of course ;)) dat je enkel adres doorgeeft (dus 4 / 8 bytes). En dit is zeker sneller als 10 of 12Kb.
Klopt totaal. Daarom zei ik ook dat je atomaire types altijd by value doet. Fyi dan heb ik het dus over ints, floats, chars en zelfs pointers (!). Een class is per definitie geen atomair type, dus altijd by const-ref.
Ivm die const-reference. Wat stel je dan zelf voor? Of hoe doe je het zelf? Als ik een const gebruik is dit met de bedoeling dat aan dat ding niets veranderd mag worden. (bvb bij "const int &I" mag I niet gewijzigd worden.
By-value is zelfs handiger voor atomairen. Denk bijvoorbeeld aan:
C++:
1
2
3
4
5
6
7
void MyWindow::Width(int p_Width)
{
// Correct non-existant width 
if(p_Width < 1)
  p_Width = 1;
.....
}

Een by-value parameter mag je wijzigen zonder dat je eerst een lokale kopie hoeft te maken: je hebt al een lokale kopie.
Ik probeer zoveel mogelijk const te gebruiken. Ik vind dit enorm handig want dan weet ik dadelijk wanneer ik ergens iets verander daar ik eigenlijk niet aan zou mogen komen.
Ook daar ben je niet consequent in O-)

Je zou nl. die operator overload ook makkelijk const kunnen maken, waarmee hij aan de boze buitenwereld meldt dat ie niets in de class verandert. Dit doe je als volgt:
C++:
1
  inline operator int() const { return m_Number; }

De extra beveiliging die dit levert is dat een const-functie zelf alleen maar andere const-functies mag aanroepen. Je garandeert niet alleen voor jezelf hiermee integriteit, de compiler kan deze informatie ook gebruiken om extra optimalisaties uit te voeren (denk aan registercaching).

Professionele website nodig?


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

curry684 schreef op 19 February 2003 @ 17:40:
De extra beveiliging die dit levert is dat een const-functie zelf alleen maar andere const-functies mag aanroepen. Je garandeert niet alleen voor jezelf hiermee integriteit, de compiler kan deze informatie ook gebruiken om extra optimalisaties uit te voeren (denk aan registercaching).


en dit is zelfs noodzakelijk als je een const Nummer wilt kunnen casten naar een int :)

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.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
curry684 schreef op 19 February 2003 @ 17:40:
Bliep klasses van 10-12Kb? Ik mag toch hopen dat dat incluis indirect gealloceerd geheugen is?
Is dat zo excessief? Ik heb weleens classes van meer dan 1Mb gehad. Goed, was een geval van een paar float[ERG_GROOT_GETAL]s, maar voor een buffertje wat je tijdelijk nodig hebt is zo'n struct vaak nodig; je wilt het nl. niet op de stack hebben.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
MSalters schreef op 19 February 2003 @ 20:31:
Is dat zo excessief? Ik heb weleens classes van meer dan 1Mb gehad. Goed, was een geval van een paar float[ERG_GROOT_GETAL]s, maar voor een buffertje wat je tijdelijk nodig hebt is zo'n struct vaak nodig; je wilt het nl. niet op de stack hebben.
Naar mijn beleving is dat wel vrij excessief, ja; meestal alloceer je je buffers onafhankelijk van je klassen, maar goed, ik kan me voorstellen dat je ze soms direct als member variables van je klasse declareert.

Ik snap alleen niet waarom grote objecten niet op de stack zouden staan en grote (andere) datastructuren wel?

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Soultaker schreef op 19 februari 2003 @ 20:51:
Naar mijn beleving is dat wel vrij excessief, ja; meestal alloceer je je buffers onafhankelijk van je klassen, maar goed, ik kan me voorstellen dat je ze soms direct als member variables van je klasse declareert.
My thoughts exactly, classes die grote arrays van floats e.d. bevatten dienen deze afzonderlijk te alloceren imho. Kun je meteen eenvoudig copy-on-demand en zo implementeren.
Ik snap alleen niet waarom grote objecten niet op de stack zouden staan en grote (andere) datastructuren wel?
Stack kun je opblazen, heap is een stuk moeilijker. :)

Professionele website nodig?


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
curry684 schreef op 19 February 2003 @ 23:34:
Stack kun je opblazen, heap is een stuk moeilijker. :)
Doch zeker niet onmogelijk. :P

Maar ik doelde eigenlijk hier op:
MSalters schreef op 19 February 2003 @ 20:31:
[...] voor een buffertje wat je tijdelijk nodig hebt is zo'n struct vaak nodig; je wilt het nl. niet op de stack hebben.
Dit begrijp ik nog steeds niet. :)

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-08 16:32
Bij welke grootte van een buffer ga jij dan een heap allocatie doen?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Voor alle duidelijkheid: ik heb het over een structure die alleen als buffer functioneert.Zodra de buffernodig is alloceer ik de structure. Zodra de functie die de buffer gebruikt returnt, gooit auto_ptr< > m'n buffer object weg. 4/8 bytes op m'nstack, 1Mb+ op heap.

Het voordeel van een heap memoryprobleem is dat j een nette std::bad_alloc krijgt. Out of stack is ongedefinieerd.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-08 16:32
Als je een dergelijk grote buffer nodig hebt zou ik die idd ook niet op de stack plaatsen. :)

2kB mag van mij nog wel, en anders maak ik het ding wel static.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

MSalters schreef op 20 February 2003 @ 10:05:
Voor alle duidelijkheid: ik heb het over een structure die alleen als buffer functioneert.Zodra de buffernodig is alloceer ik de structure. Zodra de functie die de buffer gebruikt returnt, gooit auto_ptr< > m'n buffer object weg. 4/8 bytes op m'nstack, 1Mb+ op heap.

Het voordeel van een heap memoryprobleem is dat j een nette std::bad_alloc krijgt. Out of stack is ongedefinieerd.
Volgens mij zaten we langs mekaar te praten... ik denk dat we het er allemaal over eens zijn dat releasecode geen objecten met enorme inline buffers op de stack mag flikkeren maar daarvoor netjes de heap moet aanspreken :)

Professionele website nodig?

Pagina: 1