Toon posts:

[C++] virtual-functie 'verkeerd' aangeroepen

Pagina: 1
Acties:

Verwijderd

Topicstarter
OK, ik heb dus 2 classes (3 eigenlijk, maar laten we het simpel houden).

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CLabelSoort
{
public:
  virtual long         Grootte() {return 1; }
  virtual bool SchrijfToFile        ( );
...
};

class CNormaalPakket : public CLabelSoort
{
public:
  virtual long          Grootte() { return 0; }
  virtual bool SchrijfToFile        ( );
...
};


Nu roep ik bvb:
C++:
1
2
3
CNormaalPakket np(ltInfo);
  if ( np.IsGoedLabel() )
    np.SchrijfToFile();


nu in SchrijfToFile check ik de Grootte() en ga ik daarna naar de baseclase (met CLabelSoort::SchrijfToFile();)

bvb:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
bool CNormaalPakket::SchrijfToFile()
{
  [...snip...]

  if ( !SchrijfHeaderNaarFile( fp, IsType(), Grootte() ) )
    return false;

  if ( fclose(fp) != 0 )
    return false;
  else
    return CLabelSoort::SchrijfToFile();
}


Wat ik eigenlijk beoog is dat ik mijn data die in die class zit naar de file schrijf & dan de baseclass oproep, die weer zijn data naar de file schrijft etc...

Dus mijn vraag is 2ledig:
1/ Is dit een goede manier om dit te doen? (ikzelf zet die CLabelSoort:: ... etc in al mijn derived classes)
2/ Nu als ik in CNormaalPakket zit, verwijst Grootte() naar CNormaalPakket, maar als ik dan in 'CLabelSoort::SchrijfToFile()' zit, verwijst Grootte() eveneens naar CNormaalPakket... Hoe kan ik dat oplossen?

  • whoami
  • Registratie: December 2000
  • Laatst online: 17:38
In CNormaalPakket moet je die methods Grootte en SchrijfToFile niet als virtual specifieren, maar moet je ze overriden.

code:
1
2
public:
  long override Grootte();


En ja, als je het goed doet, is het juist dat de method van de class waarin je zit opgeroepen wordt, dat is net de bedoeling van virtuele functies.
Als je de implementatie van de base class wilt oproepen vanuit CNormaalPakket dan moet je ze zo oproepen in die method:
code:
1
CBasePakket::Grootte();

[ Voor 70% gewijzigd door whoami op 05-11-2003 15:57 ]

https://fgheysels.github.io/


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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Whoami STFU, het is C++, geen C# :P ;)

[ Voor 9% gewijzigd door .oisyn op 05-11-2003 16:11 ]

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.


  • whoami
  • Registratie: December 2000
  • Laatst online: 17:38
.oisyn schreef op 05 november 2003 @ 15:56:
Whoami STFU, het is C++, geen C# :P ;)
Hmmm.... Moet je dan in C++ ook niet op de één of andere manier specifieren dat je een virtual method overrided?
Vreemd. Maar goed, ik stfu hier al.

[ Voor 2% gewijzigd door .oisyn op 05-11-2003 16:11 ]

https://fgheysels.github.io/


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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 05 november 2003 @ 15:52:
Dus mijn vraag is 2ledig:
1/ Is dit een goede manier om dit te doen? (ikzelf zet die CLabelSoort:: ... etc in al mijn derived classes)
Op zich wel, behalve dat elke methode z'n eigen file opent :?
Ik zou een FILE * als parameter mee geven, of beter nog, een std::ostream &. Dan kan er overal naar geschreven worden.
2/ Nu als ik in CNormaalPakket zit, verwijst Grootte() naar CNormaalPakket, maar als ik dan in 'CLabelSoort::SchrijfToFile()' zit, verwijst Grootte() eveneens naar CNormaalPakket... Hoe kan ik dat oplossen?
Dan moet je Grootte niet virtual maken. Of vanuit CLabelSoort gewoon Grootte aanroepen met
C++:
1
... = CLabelSoort::Grootte ();


maar zoals gezegd, dan is het nut van virtual een beetje verdwenen, dus dan kun je die ook wel weglaten :)

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: 12:02

.oisyn

Moderator Devschuur®

Demotivational Speaker

whoami schreef op 05 november 2003 @ 15:58:
[...]


Hmmm.... Moet je dan in C++ ook niet op de één of andere manier specifieren dat je een virtual method overrided?
Vreemd. Maar goed, ik stfu hier al.
ja, maar dan andersom, met virtual dus

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.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 18:33
.oisyn schreef op 05 november 2003 @ 15:56:
Whoami STFU, het is C++, geen C#
Haha, mischien moet je er nog ff een :) bijzetten voor de zekerheid.

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.


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
Verwijderd schreef op 05 november 2003 @ 15:52:
Dus mijn vraag is 2ledig:
1/ Is dit een goede manier om dit te doen? (ikzelf zet die CLabelSoort:: ... etc in al mijn derived classes)
Nee ik zou het niet zo aanpakken. Als je de SchrijfToFile() (wat een leipe naam :X) niet wil overschrijven qua gedrag, maar eerder uitbreiden, dan zou ik ervoor kiezen om dit door middel van een TemplateMethod te doen.
2/ Nu als ik in CNormaalPakket zit, verwijst Grootte() naar CNormaalPakket, maar als ik dan in 'CLabelSoort::SchrijfToFile()' zit, verwijst Grootte() eveneens naar CNormaalPakket... Hoe kan ik dat oplossen?
Natuurlijk is dat zo. Immers je impliciete eerste parameter (het object zelf) is een CNormaalPakket en die heeft een geoverride Grootte(). Als je dat niet wilt, dan kun je het Visitor pattern gebruiken met een cast, maar ik zou me eerst wel even gaan afvragen of je wel goed aan het overerven bent. Als de grootte per keer iets anders inhoud, dan vraag ik me af of je hierarchie wel klopt.

Verwijderd

Topicstarter
Mja zie, ik heb bvb hier een kleine tree:
CLabelSoort -> CNormaalPakket -> CKleinPakket -> CParcelLetter.

Dus elk heeft zijn eigen data. Dewelke ik de grootte van bepaal in de functie Grootte(). Nu wil ik natuurlijk wel als ik een CParcelLetter cast naar een CLabelSoort (bvb voor die in een set/vector ofzo te steken). dat ik dmv Grootte() uitkom bij de grootte van CParcelLetter. Conclusie: moet ik virtual gebruiken.

Maar als ik dan de boom afdaal voor naar mijn file te schrijven (en ja, elke functie schrijft naar dezelfde file, dewelke gesloten word voordat de volgende functie word opgeroepen), dan wil ik de Grootte kunnen bepalen van die class.

Dus even ter verduidelijking:
code:
1
2
3
4
5
6
7
8
9
10
11
CParcelLetter->SchrijfToFile()
--> openfile, schrijfheader, schrijfdata, sluitfile, roep CKleinPakket->SchrijfToFile();

CKleinPakket->SchrijfToFile()
--> openfile, schrijfheader, schrijfdata, sluitfile, roep CNormaalPakket->SchrijfToFile();

CNormaalPakket->SchrijfToFile()
--> openfile, schrijfheader, schrijfdata, sluitfile, roep CLabelSoort->SchrijfToFile();

CLabelSoort->SchrijfToFile()
--> openfile, schrijfheader, schrijfdata, sluitfile /*dit is einde */


Nu ja, je ziet dat dat allemaal wel een beetje op elkaar trekt hé. Ik dacht nu van 'ok, gewoon in elke class dezelfde functie gebruiken, met zelfde header etc.'. Op die manier kan ik "afdalen" [Hier komt dan eventjes een aapje kijken: Kan ik ipv altijd HANDMATIG de base-class te zetten in die derived-class-functie automatisch de baseclass-functie oproepen? bvb dmv ::SchrijfToFile(); ?]

Nu ja, voor even trug op die virtual te komen. Nu zit ik bvb in CNormaalPakket->SchrijfToFile(), en nu heb ik die functie opgeroepen dmv CParcelLetter->SchrijfToFile(). Nu als ik de grootte bepaal van de data in CNormaalPakket (dmv de functie Grootte()), refereert die naar CParcelLetter::Grootte(). Ik kan dit oplossen (zoals hier hoger vermeld) door gebruik te maken van CNormaalPakket::Grootte(), maar dan is het idioot van virtuals te gebruiken vind ik.

Dus daar zit ik een beetje in de rats mee :S

Verwijderd

Topicstarter
Glimi schreef op 05 november 2003 @ 16:08:
Als je de SchrijfToFile() (wat een leipe naam :X) niet wil overschrijven qua gedrag,
Ik own in naamgeving :) hoe dommer, hoe beter :p Zolang ik het zelf maar snap ;)


De SchrijfToFile()-functie heeft altijd dezelfde functie..., maar roept altijd de class daaronder aan... Dus met mijn beperkte kennis moet ik die in elke derived class definiëren, want ik weet niet hoe ik dat moet aanpakken dat die de baseclass pakt (zonder dat ik er hardcoded de naam inzet)

[ Voor 36% gewijzigd door Verwijderd op 05-11-2003 16:19 ]


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

.oisyn

Moderator Devschuur®

Demotivational Speaker

farlane schreef op 05 november 2003 @ 16:08:

Haha, mischien moet je er nog ff een :) bijzetten voor de zekerheid.
ja, dat bedachten glimi en ik ons ook al ;) Het zag er idd wat lullig uit voor buitenstaanders

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: 12:02

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 05 november 2003 @ 16:12:
Maar als ik dan de boom afdaal voor naar mijn file te schrijven (en ja, elke functie schrijft naar dezelfde file, dewelke gesloten word voordat de volgende functie word opgeroepen), dan wil ik de Grootte kunnen bepalen van die class.
beetje vage methode. Heb je mijn reactie (mijn 2e bedoel ik dan) al gezien?
Kan ik ipv altijd HANDMATIG de base-class te zetten in die derived-class-functie automatisch de baseclass-functie oproepen?[/i] bvb dmv ::SchrijfToFile(); ?
nee, ::SchrijftToFile () is een losse functie in de global namespace. En die bestaat waarschijnlijk niet, dus je krijgt een compile error. C++ kent ook geen keyword super zoals sommige andere talen dat wel kennen. Dat heeft te maken met het feit dat je in C++ van meerdere classes tegelijk kunt overerven (multiple inheritance heet dat)
Ik kan dit oplossen (zoals hier hoger vermeld) door gebruik te maken van CNormaalPakket::Grootte(), maar dan is het idioot van virtuals te gebruiken vind ik.

Dus daar zit ik een beetje in de rats mee :S
dat zei ik, laat dat virtual dan weg :)

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
.oisyn schreef op 05 november 2003 @ 16:19:
beetje vage methode. Heb je mijn reactie (mijn 2e bedoel ik dan) al gezien?

[...]

dat zei ik, laat dat virtual dan weg :)
1/ Jep, heb die gelezen, maar kheb er al over nagedacht en ik ga het niet doen.

2/ Mja, maar wat dan als ik een vector afloop met alle CLabelSoort'en in? en dan ->Grootte() vraag? Moet ik daar misschien een switch zetten op een virtual ->IsType()? (die functie bestaat al). Ik denk dat dit de gemakkelijkste manier is om dit op te lossen, niet?


*edit* beetje verdere uiteenzetting van 1/
Ik schrijf mijn class-data naar een queue-file. Dit is gewoon een bestandje op de harde schijf waar alle label-data gaat worden in weggeschreven. Nu elke class schrijft een header weg, gevolgd door een lengte van de trunk die erachter komt.

code:
1
2
3
4
-------header-------
type
lengte_vd_data
--------------------


Daarna volgen alle data-dingen die in de class zitten van het stramien: long (lengte van de data die volgt), data. Dus dat geeft voor de trunk:

code:
1
2
3
4
5
6
7
-------trunk-------
lengte_vd_data
data
lengte_vd_data
data
....
-------------------


Dit omdat ik met structs & strings enzo zit te werken. Dus ik kan niet bij voorbaat zeggen hoeveel plek dit gaat zijn.

Waarom ik dan geen file-pointer (of een ofstream) meegeef? Omdat ik van zodra ik een fout krijg wil kunnen false returnen (en ook omdat ik niet goed weet hoe met streams te werken). Dus bvb van zodra ik een ding niet meer naar de harde schijf kan schrijven, wil ik false kunnen returnen, of een error throwen ofzo. Op deze manier kan ik dan naar buiten springen en roepen 'Opgelet!!! HDD is volgelopen!!' of iets in die aard.

Misschien beter eens ofstream bekijken, waarschijnlijk met een try-catch oplossing dat dit evengoed zou kunnen werken...

[ Voor 54% gewijzigd door Verwijderd op 05-11-2003 16:32 ]


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

curry684

left part of the evil twins

Glimi schreef op 05 november 2003 @ 16:08:
[...]

Nee ik zou het niet zo aanpakken. Als je de SchrijfToFile() (wat een leipe naam :X) niet wil overschrijven qua gedrag, maar eerder uitbreiden, dan zou ik ervoor kiezen om dit door middel van een TemplateMethod te doen.
Anders doe jij ook STFU in C++ topics, ik moest die pagina 2 keer doorlezen voordat ik doorhad dat je een pure virtual functie bedoelde :z

Professionele website nodig?


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
curry684 schreef op 05 november 2003 @ 16:25:
Anders doe jij ook STFU in C++ topics, ik moest die pagina 2 keer doorlezen voordat ik doorhad dat je een pure virtual functie bedoelde :z
Waarom pure virtual functies? Hij hoeft niet overschreven worden hoor:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Hoeft evt niet virtual
virtual void MyClass::doSomething( ) { 
   
   preTemplateMethod();
   //the real doSomethingCode...
   postTemplateMethod();
}

//Empty
virtual void MyClass::preTemplateMethod( ) { }

//Empty
virtual void MyClass::postTemplateMethod( ) { }
}

Als je dan iets wilt uitvoeren voordat je doSomething uitvoert kan dat als volgt:
C++:
1
2
3
4
5
6
7
8
9
class MyExtendingClass: public MyClass { 
   public:
      virtual void preTemplateMethod( );
};
virtual void MyExtendingClass::preTemplateMethod( ) {

  // interesting pre-processing code here
  //
}

Wat is hier mis mee?

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

curry684

left part of the evil twins

* curry684 is de draad helemaal kwijt... dat is les 1 van virtual methods, waarom haal je daar een wazige term als templatemethod voor van stal... :?

Professionele website nodig?


Verwijderd

Topicstarter
Hier is niets mis mee.... Dat ga ik zeker gebruiken, want ik schrijf een header (pre), en post, daar roep ik dan de volgende functie in de boom aan... In de functie zelf zet ik dan enkel iets in als er data moet geschreven worden.

Mmmm, in combo met die ofstream moet dat werken... Maar ik ga zeker even thuis nachecken hoe dat streams werken... Misschien ga ik FILE* nog verafschuwen :)

Verwijderd

Topicstarter
curry684 schreef op 05 november 2003 @ 16:35:
* curry684 is de draad helemaal kwijt... dat is les 1 van virtual methods, waarom haal je daar een wazige term als templatemethod voor van stal... :?
Dat schijnt voor mij op Java te trekken :) Terminologie is anders, maar het komt ongeveer op het zelfde neer...

En ja :) veel te ingewikkeld voor mij :p Maar die laatste voorbeeldjes die hij gaf zijn me toch veel duidelijker.

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

curry684

left part of the evil twins

Je zoekt dus gewoon dit:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CLabelSoort
{
public:
  void SchrijfNaarFile()
  {
  // Open file
  ...
  SchrijfSpecifiek(...);
  ...
  // Close file
  }

protected:
  virtual void SchrijfSpecifiek(FileHandle/ostream) { }
};

Dit is zoals ik al zei erg basaal OOP werk :)

Voor alle duidelijkheid, ik was vooral in de war omdat C++ iets volslagen anders bedoelt met templates en templatemethods dan waar Glimi nu mee aan kwam :)

Professionele website nodig?


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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Die pre en post methods zijn helemaal niet nodig als je gewoon een filestream als parameter meegeeft naar je file functie.

Desnoods bouw je nog een non-virtual member die geen filestream verwacht, zodat je die daar zelf kunt openen. Zoals curry aangeeft dus

[ Voor 37% gewijzigd door .oisyn op 05-11-2003 16:44 ]

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.


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
curry684 schreef op 05 november 2003 @ 16:40:
Voor alle duidelijkheid, ik was vooral in de war omdat C++ iets volslagen anders bedoelt met templates en templatemethods dan waar Glimi nu mee aan kwam :)
Tja, sorry, dat is gewoon de naam die Erik Gamma ea aan dat pattroon gegeven hebben (zie http://home.earthlink.net/~huston2/dp/patterns.html). Dat was juist de reden dat ik er een URL bijgezet had, omdat ik er ook aan dacht dat mensen wel eens aan een template functie (alleen in Java noemen we functie's toch methods?).

Trouwens post/pre-methods staan hier nu voor z'n algemeenheid, zodat je kunt kiezen of je het wil pre-extenden of post-extenden, dat is op jouw manier niet mogelijk, als SchrijfNaarFile nog allemaal interessante dingen zou doen.

Verwijderd

Topicstarter
Ik heb het opgelost zoals curry684 het heeft voorgesteld. Gewoon een SchrijfNaarQueue() functie gemaakt die de file open & toe doet. En dan een SchrijfSpecifiek() die de data schrijft ...

Dan verder heb ik de hint van whoami gebruikt om de functie Grootte() niet meer virtual te laten zijn en de hint van .oisyn om in elke 'SchrijfSpecifiek()' expliciet te verwijzen naar de juiste class... Op deze manier kan ik gewoon niets mis meer doen ;)


En weet je wat :D Het werkt nog ook ;)

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

curry684

left part of the evil twins

Je zou bijna denken dat we hier kennis van zaken hebben ;)

Professionele website nodig?

Pagina: 1