anoniem Geplaatst: 9 november 2006 Delen Geplaatst: 9 november 2006 Ik ben een beetje aan het beginnen met c++. Ik kwam er per ongeluk achter dat het volgende niet werkt: Je hebt een hoofdklasse en een aantal subklassen. De hoofdklasse wordt in principe nooit geinstancieerd. De subklassen erven van de hoofdklasse een vector<hoofdklasse>, dus kan weer andere (subklassen van) hoofdklasse bevatten. Een boom-model dus. De hoofdklasse heeft een virtuele functie die door elke subklasse weer anders wordt 'overridden': [code:1:d6ce8cd13c] #include <iostream> #include <string> #include <vector> using namespace std; class TFiguur { public: vector<TFiguur> childs; virtual void watBenIk() {}; }; class TVierkant: public TFiguur { public: virtual void watBenIk() { cout << "Vierkant" << endl; for (unsigned i=0; i<childs.size(); i++) childs[i]->watBenIk(); // hier wordt de (lege) TFiguur:watBenIk() uitgevoerd... }; }; class TDriehoek: public TFiguur { public: virtual void watBenIk() { cout << "Driehoek" << endl; for (unsigned i=0; i<childs.size(); i++) childs[i].watBenIk(); // hier wordt de (lege) TFiguur:watBenIk() uitgevoerd... }; }; int main() { TVierkant Topnode; Topnode.childs.push_back(TVierkant()); Topnode.childs.push_back(TDriehoek()); Topnode.watBenIk(); return 0; } [/code:1:d6ce8cd13c] het is alleen zo dat bij childs[i].watBenIk() vanuit void watBenIk() niet TVierkant::watBenIk() of TDriehoek::watBenIk() wordt aangeroepen, maar de -lege- TFiguur::watBenIk(). Ik kan het oplossen door niet een vector<TFiguur> te maken maar een vector met pointers naar TFiguur: vector<TFiguur *>, en nieuwe childs toe te voegen met Topnode.childs.push_back([b:d6ce8cd13c]new[/b:d6ce8cd13c] TVierkant()/TDriehoek());. Ik vraag mij af waarom dit zo is. Kan iemand mij dit uitleggen ?[/b] Quote Link naar reactie
anoniem Geplaatst: 9 november 2006 Auteur Delen Geplaatst: 9 november 2006 (Dit hoort bij programmeren) Mijn C++ zit eerlijk gezegd ver, maar ik denk dat je constructors mist in je klassen. Quote Link naar reactie
anoniem Geplaatst: 9 november 2006 Auteur Delen Geplaatst: 9 november 2006 Omdat er geen parameters meegegeven hoeven worden aan de klassen bij het creeren, heb ik de constructors weggelaten. De compiler maakt dan zelf een defaultconstructor: TFiguur(), TVierkant() en TDriehoek(). Ik had ze idd ook zelf kunnen declareren: TFiguur() {} TVierkant():TFiguur() {} en TDriehoek():TFiguur() {} maar de werking verandert dan niet, en daar wordt het voor het topic ook niet overzichtelijker door denk ik. Quote Link naar reactie
anoniem Geplaatst: 10 november 2006 Auteur Delen Geplaatst: 10 november 2006 Default constructors ok. Maar ik denk ook dat je de basisklasse constructor in je afgeleide klasse moet aanroepen om een afgeleide klasse te kunnen krijgen. Quote Link naar reactie
anoniem Geplaatst: 10 november 2006 Auteur Delen Geplaatst: 10 november 2006 Helaas, als ik de constructors aanmaak: [code] class TFiguur { ... TFiguur() {}; ... } class TVierkant { ... TVierkant():TFiguur() {}; ... } is het resultaat hetzelfde. En hij deed het immers wel als ik slechts de member vector<TFiguur> wijzigde in vector<TFiguur* > ! Daarom snap ik het ook niet echt. Quote Link naar reactie
anoniem Geplaatst: 13 november 2006 Auteur Delen Geplaatst: 13 november 2006 Niks geen extra constructors/destructors toevoegen (is alleen nodig om straks 'childs' goed te initialiseren). Het voorbeeld dat je gebruikt is gewoon onnodig complex om de fout te vinden. Daarnaast is er een belangrijke fout in de afgeleidde klassen. [code:1:06b8753c3f]virtual[/code:1:06b8753c3f] moet [code:1:06b8753c3f]overload[/code:1:06b8753c3f] zijn. Zoals jij ze nu hebt gedefinieerd zal de compiler je waarschijnlijk warnings geven in de trend van "watBenIk(); is already defined ..." Dit voorbeeld is simpeler en werkt beter : [code:1:06b8753c3f] void main() { TFiguur mijnDemo; mijnDemo = new TVierkant(); mijnDemo.watBenIk(); // resultaat : een vierkant ... } [/code:1:06b8753c3f] Stap eerst eens af van dat die interne variabele 'childs' van het vektor-type want dat verwart alleen maar het voorbeeld. De enige manier om in jouw voorbeeld die driehoek/vierkant terug te krijgen is om ze via childs-property op te halen. Topnode is in jouw voorbeeld namelijk gewoon een instantie van het type TFiguur. Het is dus voor mij redelijk logisch dat [code:1:06b8753c3f]Topnode.watBenIk();[/code:1:06b8753c3f] niks oplevert. Quote Link naar reactie
anoniem Geplaatst: 16 november 2006 Auteur Delen Geplaatst: 16 november 2006 Je moet een vector maken van TFiguur pointers, want als je het in deze opstelling doet (op de stack), dan kun je geen gebruik maken van de zogenaamde polymorfe eigenschappen van je object. 8) Zoiets dus: [code:1:38c9a5fbf7]#include <iostream> #include <string> #include <vector> using namespace std; class TFiguur { public: vector<TFiguur*> childs; //< Pointer hier virtual void watBenIk() {}; }; class TVierkant: public TFiguur { public: virtual void watBenIk() { cout << "Vierkant" << endl; for (unsigned i=0; i<childs.size(); i++) childs[i]->watBenIk(); }; }; class TDriehoek: public TFiguur { public: virtual void watBenIk() { cout << "Driehoek" << endl; for (unsigned i=0; i<childs.size(); i++) childs[i]->watBenIk(); }; }; int main() { TVierkant Topnode; Topnode.childs.push_back(new TVierkant()); //< New operator Topnode.childs.push_back(new TDriehoek()); Topnode.watBenIk(); return 0; }[/code:1:38c9a5fbf7] Vergeet wel niet dat je alle objecten die je met een new-operator aanmaakt, ook weer moet opruimen met delete he. Want deze code lekt geheugen. Daar kun je een virtual destructor in TFiguur voor gebruiken. Enne, JaFO... van dat overload-keyword had ik nog nooit gehoord. Ik heb even gegoogled, en ben tot de conclusie gekomen dat het een overbodig sleutelwoord is en door nieuwe compilers niet eens meer ondersteund wordt. Dus ik denk niet dat dat een goede oplossing is. Tenzij musicom76 ook met zo'n oude compiler werkt. ;) Quote Link naar reactie
anoniem Geplaatst: 17 november 2006 Auteur Delen Geplaatst: 17 november 2006 tja ... ben dan ook geen expert op C++ gebied ;) C# kent het weer wel dacht ik ... gezien de aard van het probleem leek het of dat de oorzaak van de fout was. En zelf destructors aanroepen ? Dat is ook zoiets ouderwets ... :p 'moderne' compilers zijn namelijk zo slim om zelf van instanties de destructor weg te gooien. Enige nadeel is dat je dan geen controle hebt over het moment van destructie. De .Net-talen doen dat in ieder geval zo. Waarom zou je geen gebruik kunnen maken van polymorphy als het 'maar' pointers zijn ? Je typecast het ding naar 'pointer' om het op de stack te kieperen en als je het er af haalt dan typecast je die 'pointer' naar de basisklasse (TFiguur in dit geval). Quote Link naar reactie
anoniem Geplaatst: 18 november 2006 Auteur Delen Geplaatst: 18 november 2006 [quote:41e925c602="JaFO"]'moderne' compilers zijn namelijk zo slim om zelf van instanties de destructor weg te gooien. Enige nadeel is dat je dan geen controle hebt over het moment van destructie. De .Net-talen doen dat in ieder geval zo.[/quote:41e925c602] Dat zou ik weer niet weten... leren we weer wat van elkaar. :) Maar bij 'gewone' C++ is het zo dat een object aleen automatisch wordt opgeruimd als het op de stack gecreeerd is (dus geen pointer of reference). Over een pointer heb je daarentegen zelf de verantwoordelijkheid om een instantie van een object zelf aan te maken en te verwijderen. Sommigen ervaren dat als lastig (want als je niet oplet krijg je een geheugen-lek), en voor sommigen geeft het een gevoel van directe controle. [quote:41e925c602="JaFO"]]Waarom zou je geen gebruik kunnen maken van polymorphy als het 'maar' pointers zijn ? Je typecast het ding naar 'pointer' om het op de stack te kieperen en als je het er af haalt dan typecast je die 'pointer' naar de basisklasse (TFiguur in dit geval).[/quote:41e925c602] Dat is nu precies wat die polymorfie inhoudt. Je 'cast' een TVierkant* naar een TFiguur* (weliswaar impliciet). En toch reageert die instantie anders dan een instantie van de basisklasse TFiguur. Dit kan een wenselijke eigenschap zijn. Waarom dit alleen geldt voor pointers is ergens ook wel logisch. Als je een nieuw object maakt door te zeggen "TFiguur eenFiguur", dan geef je tijdens het compileren al aan dat "eenFiguur" van het type TFiguur is, en kan het ook niets anders zijn. Wanneer je zegt "TFiguur* eenFiguur" dan kun je achteraf een instantie van -een- TFiguur eraan hangen en is dus niet zeker of het om een TFiguur of misschien om een TVierkant gaat. Quote Link naar reactie
Aanbevolen berichten
Om een reactie te plaatsen, moet je eerst inloggen