Toon posts:

[C++] Lijst met verschillende object-types

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik probeer in C++ iets te doen met lijsten van verschillende objecten, maar heb wat probleempjes met het accessen van afgeleide classes. Meer concreet, ik heb de volgende base class:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define SQUARE 10 
//etc

class rrObject {

protected: 
  rrVector color;   // color of the 2D object
  bool visibility;  // true if visible
  int objectType;   // type of object (SQUARE, RECTANGLE or TRIANGLE)
  // etc

public: 
  void setVisibility (bool vis);
  bool getVisibility ();
  short getObjectType ();
  // etc
};


En een aantal afgeleide classes, bijvoorbeeld rrSquare:

code:
1
2
3
4
5
6
7
8
9
10
11
12
class rrSquare: public rrObject {
private:
  rrVector position; // position of the left-top corner
  double size; // size 
  
public:
  rrSquare();
  rrSquare(rrVector pos, rrVector norm, int s, rrVector col, bool vis);
  void setSize(double s);
  double getSize();
  // etc
};


Nu wil ik een lijst implementeren die allerlei verschillende objecten kan bevatten (squares, triangles, spheres, etc). Dit heb gedaan als volgt:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class rrObjectGroup {
 
public:
  rrObject object[MAX_OBJECTS]; // list of 2D en 3D objects
  int count; // number of objects in list

  // constructors
  rrObjectGroup ();

  // object manipulators
  void addObject (rrObject obj);  // add an rrLightNode
  void removeObject (int num);  // remove an rrLightNode
  int getCount(); // return count

};


Tot zover gaat het goed. Ik kan met addObject(..) ook netjes bijvorrbeeld een rrSquare object in de lijst gooien. Het probleem is echter dat ik daarna de data van de afgeleide classes niet meer terug kan vinden.

Ik wil ergens anders bijvoorbeeld het volgende doen:

code:
1
      drawSquare(objectGroup.object[i]);


drawSquare verwacht een rrSquare object, dus dit werkt niet. Ik heb het toen gewijzigd in:

code:
1
      drawSquare((rrSquare*) &objectGroup.object[i]);


... dit is compileerbaar, maar als ik nu bijvooreeld square.getSize() doe in die drawSquare(rrSquare square) { .. } method, dan levert ie altijd 0 op, ongeacht waar ik de size op het ingesteld. Ik kan de data uit de base class echter nog wel benaderen; als ik bijvoorbeeld square.getObjectType(); doe komt er netjes 10 uit (en dit klopt -- zie #def).

Ik heb het eea gelezen over polymorfisme, maar ik denk niet dat dat hier echt van toepassing is, aangezien ik niet 1 en dezelfde functie voor verschillende objecten wil definieren. Een rrSquare heeft bijvoorbeeld een size, maar een rrSphere heeft dit niet (maar een radius), etc, dus de objecten zullen ook verschillende methods bezitten (getSize, getRadius, etc).

Ik vraag me nu twee dingen af:
1. Bezit de lijst zoals ik die nu heb geimplementeerd alleen info over de base classes, of ook wel degelijk over de afgeleide classes?
2. Indien het tweede, dan lijkt het me dat ik die informatie op de eoa manier ook weer moet kunnen accessen; maar bovenstaande casting-methode lijkt dus niet te werken :( Waarom niet? En hoe moet het dan wel?

Ik herinner met dat ik iets dergelijks ook ooit in Java heb gedaan en daar was het volgens mij niet zo'n probleem...

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
Je hebt last van object splicing.

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
farlane schreef op 03 april 2004 @ 13:27:
Je hebt last van object splicing.
Object splicing? Dat zou betekenen dat de compiler niet weet van welke class hij een bepaalde functie moet uitvoeren toch? Maar dat lijkt me geen probleem, aangezien een method als getSize() alleen voor de rrSquare is gedefinieerd... Toch??

  • AaroN
  • Registratie: Februari 2001
  • Laatst online: 16-08-2023

AaroN

JayGTeam (213177)

In dit geval kun je met dynamic_cast rrObject weer terugcasten naar de deravitive die je wenst. Als het object van de te casten class is, zul je een pointer terugkrijgen, anders null.

Zie MSDN voor meer info. Die informatie van die objecten ligt nog steeds in de virtual function tables opgeslagen, dus dat probleem zal toch met polymorfisme te maken hebben.

EDIT: Idd dat verhaal van pointers (zie farlane) even overhet hoofd gezien 8)7

[ Voor 20% gewijzigd door AaroN op 03-04-2004 13:36 ]

JayGTeam (213177)


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
Doordat je de objecten als 'value objecten' opslaat, wordt er door de compiler een stuk van het object weggegooit, namelijk alle specifieke dingen die niet in je object class zitten.

Probeer je lijst klasse maar eens zo te schrijven dattie een lijst van pointers naar objecten bijhoudt, dan heb je dat probleem niet.

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.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
AaroN schreef op 03 april 2004 @ 13:34:
In dit geval kun je met dynamic_cast rrObject weer terugcasten naar de deravitive die je wenst.
Nee, dat werkt alleen als het object nog intact is, dat is hier niet het geval.

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
farlane schreef op 03 april 2004 @ 13:36:
[...]


Nee, dat werkt alleen als het object nog intact is, dat is hier niet het geval.
Ik zal het eens met een pointerlijst (+ dynamic_cast) proberen. Bedankt!

  • whoami
  • Registratie: December 2000
  • Laatst online: 26-05 23:32
Waarom zou polymorphisme hier niet van toepassing kunnen zijn?
Maak die functies virtual, en doe zoals farlane zegt: maak die objecten op de heap:

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
25
class Base
{
    public:
         virtual double GetSize() =0;
};

class Inherited : Base
{
    public:
         virtual double GetSize()
          {
                return .... ;
          }
};

....

Base* blaat[2];
blaat[0] = new Inherited();
blaat[1] = new Inherited();

for( int i = 0; i < 2; i++ )
{
    blaat[i]->GetSize();
}

https://fgheysels.github.io/


Verwijderd

Topicstarter
whoami schreef op 03 april 2004 @ 13:44:
Waarom zou polymorphisme hier niet van toepassing kunnen zijn?
Maak die functies virtual, en doe zoals farlane zegt: maak die objecten op de heap:
Hmm, dit zal ik inderdaad maar 's gaan proberen, want nu ik er een pointer-lijst van het gemaakt begint ie alsnog te zeuren (en een hint te geven in de richting van polymorfisme ;-)):

---
rrScene.cpp:38: cannot dynamic_cast `
this->rrScene::objectGroup.rrObjectGroup::object[i]' (of type `class
rrObject*') to type `class rrSquare*' (source type is not polymorphic)
---

Maar moet ik dan niet voor elke afgeleide class alle in de base class gedeclareerde virtual methods gaan implementeren? Dat zou namelijk nogal onhandig zijn, want ik ben van plan een redelijke zooi 2D- en 3D-objecten te gaan definieren (en het is wat stom om voor elk object bijv. een getRadius() en setRadius() te gaan implementeren terwijl deze alleen maar van toepassing is op Spheres en en circles). Naja, ik zie eerst wel even wat de compiler er van zegt als ik 'm alleen voor die objecten definieer.

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Verwijderd schreef op 03 april 2004 @ 13:39:
[...]

Ik zal het eens met een pointerlijst (+ dynamic_cast) proberen. Bedankt!
Ga _nooit_ in je ontwerp al met dynamic_cast werken. Die cast is evil, en eigenlijk alleen nuttig in gevallen dat je een andere library gebruikt oid. Het is een hack, laat je ontwerp niet onstaan uit een hack.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
Verwijderd schreef op 03 april 2004 @ 13:57:
Hmm, dit zal ik inderdaad maar 's gaan proberen, want nu ik er een pointer-lijst van het gemaakt begint ie alsnog te zeuren (en een hint te geven in de richting van polymorfisme ;-)):

---
rrScene.cpp:38: cannot dynamic_cast `
this->rrScene::objectGroup.rrObjectGroup::object[i]' (of type `class
rrObject*') to type `class rrSquare*' (source type is not polymorphic)
---
Heb je er aan gedacht dat je addObject functie ook een pointer of reference neem ? Anders heb je namelijk nog steeds last van object splicing.

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
Hmm, het lijkt er op dat ik nu inderdaad voor iedere subclass ELKE gedeclareerde virtual method moet gaan implementeren:

--------
rrObject.o(.gnu.linkonce.d._ZTV10rrCylinder+0x8): undefined reference to `rrObject::setSize(double)'
rrObject.o(.gnu.linkonce.d._ZTV10rrCylinder+0xc): undefined reference to `rrObject::getSize()'
rrObject.o(.gnu.linkonce.d._ZTV9rrPyramid+0x8): undefined reference to `rrObject::setSize(double)'
rrObject.o(.gnu.linkonce.d._ZTV9rrPyramid+0xc): undefined reference to `rrObject::getSize()'
rrObject.o(.gnu.linkonce.d._ZTV8rrSphere+0x8): undefined reference to `rrObject::setSize(double)'
rrObject.o(.gnu.linkonce.d._ZTV8rrSphere+0xc): undefined reference to `rrObject::getSize()'
rrObject.o(.gnu.linkonce.d._ZTV5rrBox+0x8): undefined reference to `rrObject::setSize(double)'
rrObject.o(.gnu.linkonce.d._ZTV5rrBox+0xc): undefined reference to `rrObject::getSize()'
rrObject.o(.gnu.linkonce.d._ZTV6rrCube+0x8): undefined reference to `rrObject::setSize(double)'
rrObject.o(.gnu.linkonce.d._ZTV6rrCube+0xc): undefined reference to `rrObject::getSize()'
rrObject.o(.gnu.linkonce.d._ZTV10rrTriangle+0x8): undefined reference to `rrObject::setSize(double)'
rrObject.o(.gnu.linkonce.d._ZTV10rrTriangle+0xc): undefined reference to `rrObject::getSize()'
rrObject.o(.gnu.linkonce.d._ZTV11rrRectangle+0x8): undefined reference to `rrObject::setSize(double)'
rrObject.o(.gnu.linkonce.d._ZTV11rrRectangle+0xc): undefined reference to `rrObject::getSize()'
.
.
.
[KNIP]
-----------

Ik heb getSize alleen voor de Square gedefinieerd, omdat deze niet van toepassing is op spheres, cylinders, pyramids, etc.

En m'n reden om in dit stadium geen gebruik te maken van polymorfisme was precies omdat ik hier al bang voor was :( Op deze manier krijgt ieder object een 'overhead' van zo'n meer dan 20 'lege' functies ben ik bang en dat vind ik nou ook niet echt handig / mooi.

Wat ik wil lijkt me niet zo complex te zijn eigenlijk:

1. Een base class maken met verschillende sub classes, zonder virtual functions, maar wel met een aantal gedeelde functies (getVisibility() etc) en een aantal object-specifieke functie (getSize, getRadius, getWidth, etc).
2. Een lijst creeren die pointers bevat naar dergelijke objecten (i.e. naar rrSquares, rrSpheres, rrRectangles, rrCubes, etc etc)
3. Deze objecten ergnes anders weer uit die lijst halen
4. met een Object.getType() erachter komen wat voor subclass er onder de betreffende base class hangt
5. met een case statement verschillende Draw(....) functies aanroepen (e.g. drawSquare(rrSquare obj) wanneer object.getType() = SQUARE)

Ik heb het idee dat ik al een heel eind was, maar dat de laatste stap (het terugcasten van een object uit de lijst naar de gewenste subclass) niet helemaal goed ging (zie m'n eerste post).

Pff.. ik ga nog maar even wat met pointerlijsten + dynamic_cast klooien....

Bedankt voor de suggesties iig

[ Voor 7% gewijzigd door Verwijderd op 03-04-2004 14:23 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 26-05 23:32
Mjah, misschien heb je gewoon geen goede class-hierarchy uitgedacht.

https://fgheysels.github.io/


Verwijderd

Topicstarter
whoami schreef op 03 april 2004 @ 14:22:
Mjah, misschien heb je gewoon geen goede class-hierarchy uitgedacht.
Hmm, goed punt ;)

Maar volgens mij werkt het al, zonder virtual methods en zonder dynamic_casting. Die lijst bevat nu pointers en de drawWhateverObject(...) routines worden nu als volgt aangeroepen:
code:
1
2
3
4
5
    switch (objectGroup.object[i]->getObjectType()) {
    case SQUARE:
      drawSquare((rrSquare*)objectGroup.object[i]);
    case TRIANGLE:
      drawTriangle((rrTriangle*)objectGroup.object[i]);


Dit is eigenlijk wat ik de hele tijd al wilde, maar dit werkte eerst niet (waarschijnlijk eoa domme fout van mijn kant); ik kreeg steeds meldingen dat casting van rrObject* naar rrSquare* niet mogelijk was, waardoor ik ging denken dat C++ dat om eoa reden niet toestond... Het lijkt dus weer 's een geval te zijn waarin je een halve dag allerlei onnodig complexe trucs gaat uitproberen doordat je een stomme tikfout hebt gemaakt (eerder regel dan uitzondering bij mij, hehe)

Naja, i.i.g. bedankt voor jullie medeleven ;-))

  • whoami
  • Registratie: December 2000
  • Laatst online: 26-05 23:32
Verwijderd schreef op 03 april 2004 @ 14:36:
[...]


Hmm, goed punt ;)

Maar volgens mij werkt het al, zonder virtual methods en zonder dynamic_casting. Die lijst bevat nu pointers en de drawWhateverObject(...) routines worden nu als volgt aangeroepen:
code:
1
2
3
4
5
    switch (objectGroup.object[i]->getObjectType()) {
    case SQUARE:
      drawSquare((rrSquare*)objectGroup.object[i]);
    case TRIANGLE:
      drawTriangle((rrTriangle*)objectGroup.object[i]);
Dat werkt dan inderdaad, maar dan kan je je afvragen of dit wel mooi is.
Ik bedoel, waarom is polymorphisme uitgevonden denk je?
Als je nu een nieuwe subclass maakt, dan moet je overal waar je bovenstaande structuur hebt gebruikt, je code gaan nalopen en aanpassen.

https://fgheysels.github.io/


Verwijderd

Wanneer je een functie virtual maakt hoef je hem niet perse in elke afgeleidde te implementeren, dat doe je alleen maar wanneer je er in een afgeleide er een andere werking aan wilt geven.
bijvoorbeeld het berekenen van de oppervlakte van een cirkel is anders dan van een rechthoek.

Wanneer je een functie puur virtual maakt vb int getSize()=0; Dan moet het wel, maar virtual geeft alleen maar aan dat je hem een andere werking kan geven.

Verder vraag ik me af of die 'switch' nou wel zo'n mooie oplossing is want het maakt het geheel wel een stuk minder onderhoudbaar. Je zei namelijk dat je nog veel meer type wou implementeren naast square enz. Dan zou je straks overal een switch moeten maken met al die mogelijkheden.
Als je er dan later weer 1 type bij maakt moet je dat overal weer aan passen. Ik vermoed dat je beter nog even door kan puzzelen voor OOP oplossing.

Verwijderd

Topicstarter
Verwijderd schreef op 03 april 2004 @ 14:48:
[knip]

Ik vermoed dat je beter nog even door kan puzzelen voor OOP oplossing.
Ja, je hebt gelijkt. Het is waarschijnlijk wat eleganter om die daw() method als virtual method aan de objecten zelf te koppelen, i.p.v. ze ergens anders te implementeren (en verschillende namen te geven).

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Misschien doe je er goed aan dit eens door te lezen:

http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.6

En ook de andere hoofdstukken over inheritance.

[ Voor 19% gewijzigd door Zoijar op 03-04-2004 15:14 . Reden: url tag ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoijar schreef op 03 april 2004 @ 14:08:
[...]

Ga _nooit_ in je ontwerp al met dynamic_cast werken. Die cast is evil, en eigenlijk alleen nuttig in gevallen dat je een andere library gebruikt oid. Het is een hack, laat je ontwerp niet onstaan uit een hack.
Ik vind dat maar een lugubere uitspraak, waarom zou dynamic_cast evil zijn? En een hack??? Misschien ben je in de war met reinterpret_cast?

dynamic_cast is een volledig nette OO constructie om te controleren of een bepaald object van een bepaald subtype is van het type dat je hebt. Het is in geval van up downcasting bij polymorphe klassen eigenlijk beter dan static_cast, omdat je dan @ runtime kunt controleren of het wel klopt (een verkeerde dynamic_cast op een reference gooit een exception, eentje op een pointer retourneert NULL)

[ Voor 31% gewijzigd door .oisyn op 03-04-2004 17:16 ]

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.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

.oisyn schreef op 03 april 2004 @ 16:32:
Ik vind dat maar een lugubere uitspraak, waarom zou dynamic_cast evil zijn? En een hack??? Misschien ben je in de war met reinterpret_cast?
Nee, ik ben niet in de war :) dynamic_cast is een runtime iets, je kan dus pas zien of/dat het mis gaat at runtime. Misschien is dat wel meteen, maar misschien is dat ook pas als de shuttle al is gelanceerd.
Verder, waarom zou je eerst een algemene input vragen, en daar dan iets specifieks van gaan maken. Dat is al een vreemd iets in je otnwerp.
Meestal duiden downcasts dan ook op een fout in het ontwerp.
dynamic_cast is een volledig nette OO constructie om te controleren of een bepaald object van een bepaald subtype is van het type dat je hebt. Het is in geval van upcasting bij polymorphe klassen eigenlijk beter dan static_cast, omdat je dan @ runtime kunt controleren of het wel klopt (een verkeerde dynamic_cast op een reference gooit een exception, eentje op een pointer retourneert NULL)
Dit snap ik niet (typo?), upcast gaat altijd goed...of niet, maar dat is @ compile time. En een downcast kan helemaal niet als static_cast. In principe is dynamic_cast niet evil, maar zijn downcasts dat. En ja, als je daar dan toch niet omheen kan (wat in zeldzame gevallen misschien wel eens waar is) dan is dynamic_cast wel de beste manier.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoijar schreef op 03 april 2004 @ 17:04:
[...]

Nee, ik ben niet in de war :) dynamic_cast is een runtime iets, je kan dus pas zien of/dat het mis gaat at runtime. Misschien is dat wel meteen, maar misschien is dat ook pas als de shuttle al is gelanceerd.
Verder, waarom zou je eerst een algemene input vragen, en daar dan iets specifieks van gaan maken. Dat is al een vreemd iets in je otnwerp.
Meestal duiden downcasts dan ook op een fout in het ontwerp.
Ik haal maar even een typisch voorbeeld uit java aan, omgezet naar C++ :)

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Object
{
public:
    virtual bool equals (const Object & other)
    {
        return this == &other;
    }
};

class String : public Object
{
private:
    char * buffer;

public:
    bool equals (const Object & other)
    {
        if (this == &other)
            return true;
        String * s = dynamic_cast<String *> (&other);
        return s && !strcmp (buffer, s->buffer);
    }
};


Perfecte valide OO code imho, niet te doen zonder downcast
Dit snap ik niet (typo?)
euh ja downcast bedoel ik idd, stom |:(

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.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Ja, goed voorbeeld :) Maar is dit dan echt nuttig? Wil je echt appels met peren vergelijken? ;) Of is er, als je dat doet, eigenlijk al ergens anders iets mis? Stel je wilt weten of twee autos gelijk zijn, want dan kan de tweede naar de sloop. Vrolijk vergelijk je een fiets met die nieuwe mercedes...

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je zou toch kunnen vergelijken of Jantje met eenzelfde voertuig naar z'n werk is gegaan als Pietje? :) Of er staat een auto fout geparkeerd en je wilt de werknemer even inlichten, en dus moet je even zoeken van wie de auto is door een lijst met voertuigen van werknemers af te zoeken naar gelijkenis. Een typisch geval waarbij er objecten van hetzelfde basistype, maar wellicht verschillende derived typen, in dezelfde container staan, en je zoekt naar een specifiek object in de container :)

Ik ben het met je eens dat downcasts vaak een fout ontwerp betekenen hoor, maar om nou te zeggen dat ze evil zijn, en dynamic_cast dus ook, vind ik een beetje ver gaan ;)

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: 09-04 22:08
.oisyn schreef op 03 april 2004 @ 17:16:
[...]


Ik haal maar even een typisch voorbeeld uit java aan, omgezet naar C++ :)

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Object
{
public:
    virtual bool equals (const Object & other)
    {
        return this == &other;
    }
};

class String : public Object
{
private:
    char * buffer;

public:
    bool equals (const Object & other)
    {
        if (this == &other)
            return true;
        String * s = dynamic_cast<String *> (&other);
        return s && !strcmp (buffer, s->buffer);
    }
};


Perfecte valide OO code imho, niet te doen zonder downcast
Nee?
Dus wel:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
clas String;
class Object {
  virtual bool operator==( Object const& ) = 0 ;
  virtual bool operator==( String const& ) { return false; }
};
class String {
  virtual bool operator == ( String const& rhs) { ... };
  virtual bool operator == ( Object const& rhs )
  { 
     return rhs == *this;
  }
};

De truc is dat de laatste operator== de argumenten omdraait, zodat je eerst polymorphisme gebruikt op het eerste argument en daarna op het initieel tweede element.

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


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

MSalters schreef op 03 april 2004 @ 21:25:
De truc is dat de laatste operator== de argumenten omdraait, zodat je eerst polymorphisme gebruikt op het eerste argument en daarna op het initieel tweede element.
En dat kan je weer mooi automatisch (compiletime) genereren voor je class hierarchy met template typelists (ala loki) :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

MSalters schreef op 03 april 2004 @ 21:25:
De truc is dat de laatste operator== de argumenten omdraait, zodat je eerst polymorphisme gebruikt op het eerste argument en daarna op het initieel tweede element.
Lekker onderhoudbaar, moet je in de baseclass alle derived classes gaan specificeren. Dat noem ik nog eens een slecht ontwerp

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.

Pagina: 1