[c++] makkelijke manier om parent te accesen vanuit child

Pagina: 1
Acties:

  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
goedesmiddags :)

Ik ben al enige tijd bezig met een soort game engine op aant zetten, maar nu loop ik tegen iets op waarbij ik me afvraag, 'dat moet toch makkelijker kunnen'.

Ik heb een class manipulate die child kan worden van een ander object, waarop deze 'manipuleerbaar' wordt. Het probleem is, dat zowel het object als de classe manipulate kennis willen hebben van het spel waar ze in draaien (game).
Nu geef ik 'game' in principe altijd mee als ik een nieuw object maak, dus kan ik deze ook doorgeven. aan manipulate.
zo heb ik het nu dan ook opgelost:
object heeft een pointer naar game
manipulate heeft een pointer naar object.

Zo kan ik dus altijd aan alle info komen, maar er staat tegenover dat ik in de constructor van object altijd de pointer van manipulate moet toewijzen.

Nu vroeg ik me af of dit niet makkelijker kan op een of andere manier. Dat manipulate bv automatisch de pointer naar game van zijn parentobject mag gebruiken.

ik ben benieuwd :)

oprecht vertrouwen wordt nooit geschaad


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 15-02 11:20
Atgast schreef op woensdag 28 juni 2006 @ 14:40:
Nu vroeg ik me af of dit niet makkelijker kan op een of andere manier. Dat manipulate bv automatisch de pointer naar game van zijn parentobject mag gebruiken.
Dan moet maniulate dus een referentie hebben naar zijn parent en de parent een public of friend functie die de pointer naar game teruggeeft.

Of dit de correcte manier is is afhankelijk van de correctheid van je ontwerp :)

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.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 15-02 21:33
Zo kan ik dus altijd aan alle info komen, maar er staat tegenover dat ik in de constructor van object altijd de pointer van manipulate moet toewijzen.
Hier raak ik je kwijt...? Hoe kan de constructer van Object ooit een 'pointer van Manipulate' toewijzen?
Nu vroeg ik me af of dit niet makkelijker kan op een of andere manier. Dat manipulate bv automatisch de pointer naar game van zijn parentobject mag gebruiken.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Game { .. };

class Object {
    Game *game;
public:
    inline Game *getGame() { return game; }
};

class Manipulate {
    Object *object;
public:
    inline Game *getGame() { return object->getGame; }
};
Zoiets :?
Trouwens, Object is een nogal ongelukkige naam voor een klasse (tenzij je van plan bent 'm als basis voor andere klassen te gebruiken, misschien). Je kunt verder ook overwegen om references in plaats van pointers te gebruiken, als de pointers nooit NULL zijn en gedurende de levensduur van de objecten niet veranderen.

  • mOrPhie
  • Registratie: September 2000
  • Laatst online: 29-01 12:00

mOrPhie

❤️❤️❤️❤️🤍

Kun je trouwens meerdere instanties van game hebben of werkt game meer als kernel voor de rest van de klasses? In het 2e geval zou je kunnen overwegen om game singleton te maken. :)

Een experimentele community-site: https://technobabblenerdtalk.nl/. DM voor invite code.


  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
mOrPhie schreef op woensdag 28 juni 2006 @ 16:36:
Kun je trouwens meerdere instanties van game hebben of werkt game meer als kernel voor de rest van de klasses? In het 2e geval zou je kunnen overwegen om game singleton te maken. :)
Het is uiteindelijke de bedoeling dat er meerdere games naast elkaar kunnen draaien.
Soultaker schreef op woensdag 28 juni 2006 @ 16:31:
[...]

Hier raak ik je kwijt...? Hoe kan de constructer van Object ooit een 'pointer van Manipulate' toewijzen?


[...]

Trouwens, Object is een nogal ongelukkige naam voor een klasse (tenzij je van plan bent 'm als basis voor andere klassen te gebruiken, misschien). Je kunt verder ook overwegen om references in plaats van pointers te gebruiken, als de pointers nooit NULL zijn en gedurende de levensduur van de objecten niet veranderen.
De namen zijn slechts fictief.
Ik zal proberen mijn bedoeling met simpele code duidelijk te maken
C++:
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
26
class Game {
    std::string name = "aapje";
};

class Manipulate {
    std::string getName() { return game->name; }
};

class ObjectA: public Manipulate {
    ObjectA(Game* g) { game = g; }
    Game *game;
};

class ObjectB: public Manipulate {
    ObjectB(Game* g) { game = g; }
    Game *game;
};

// in de main:
Game* game = new Game();

ObjectA* test1 = new ObjectA(game);
ObjectB* test2 = new ObjectB(game);

cout << test1->getName() << endl;
cout << test2->getName() << endl;
Los van het feit dat er wel meer niet kan met deze code, gaat het erom dat de getName functie van Manipulate natuurlijk gaat klagen over het niet kennen van de variabele game.

oprecht vertrouwen wordt nooit geschaad


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Waarom maak je in Manipulate dan niet een abstracte method GetGame. De class die Manipulate dan overerft implementeerd die dan gewoon.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 15-02 21:33
Ik volg het nog steeds niet helemaal. Als alle instanties van Manipulate (of subklassen) een Game* member hebben, zet 'm dan ook in Manipulate:
C++:
1
2
3
4
5
6
7
8
9
10
class Manipulate {
  Game *game;
public:
  Manipulate(Game *g) : game(g) { ... };
};

class ObjectX : public Manipulate {
public:
  ObjectX(Game *g) : Manipulate(g) { ... } ;
};

Als Manipulate wel dingen moet doen met een game maar het van de subklasse afhangt waar 'ie vandaan komt, dan is een virtual method waarschijnlijk wel handig. Dat is ook de suggestie die rwb doet:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
class Manipulate {
public:
  virtual Game *getGame() = 0;
  string getName() { return getGame()->name; }
};

class ObjectX : public Manipulate {
  Game *game;
public:
  ObjectX(Game *g) : game(g) { ... };
  Game *getGame() { return game; }
};


Eigenlijk lijkt het eerste scenario me een stuk zinniger, tenzij er een reden is waarom Manipulate niet al een referentie naar Game zou hebben.

  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
Soultaker schreef op woensdag 28 juni 2006 @ 20:00:
Ik volg het nog steeds niet helemaal. Als alle instanties van Manipulate (of subklassen) een Game* member hebben, zet 'm dan ook in Manipulate:
C++:
1
2
3
4
5
6
7
8
9
10
class Manipulate {
  Game *game;
public:
  Manipulate(Game *g) : game(g) { ... };
};

class ObjectX : public Manipulate {
public:
  ObjectX(Game *g) : Manipulate(g) { ... } ;
};

Als Manipulate wel dingen moet doen met een game maar het van de subklasse afhangt waar 'ie vandaan komt, dan is een virtual method waarschijnlijk wel handig. Dat is ook de suggestie die rwb doet:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
class Manipulate {
public:
  virtual Game *getGame() = 0;
  string getName() { return getGame()->name; }
};

class ObjectX : public Manipulate {
  Game *game;
public:
  ObjectX(Game *g) : game(g) { ... };
  Game *getGame() { return game; }
};


Eigenlijk lijkt het eerste scenario me een stuk zinniger, tenzij er een reden is waarom Manipulate niet al een referentie naar Game zou hebben.
Ik denk dat ik het nu begrijp, voor mijn geval zou de eerste optie waarschijnlijk het handigste zijn ja.
Begrijp ik het goed als ik zeg dat je een virtual member als een soort forward declaratie zou kunnen zien (mar dan dus voor een functie) ?

oprecht vertrouwen wordt nooit geschaad


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 15-02 21:33
Atgast schreef op woensdag 28 juni 2006 @ 20:13:
Begrijp ik het goed als ik zeg dat je een virtual member als een soort forward declaratie zou kunnen zien (mar dan dus voor een functie) ?
Hmm, een forward declaration zou ik het niet willen noemen. Het verschil tussen een virtual en een non-virtual method is dat bij de non-virtual method al tijdens het compileren, op basis van het type van de variabele, bepaald wordt welke methode aangeroepen wordt, terwijl dat bij een virtual method at runtime wordt bepaald, aan de hand van het feitelijke type van het object.

Nogal een ingewikkelde zin, dus een kort voorbeeld:
C++:
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 A {
public:
  int f() { return 1; }
  virtual int g() { return 2; }
};

class B : public A {
public:
  int f() { return 3; }
  int g() { return 4; }
  // Dit kan ook, en is equivalent:
  // virtual int g() { return 4; }
};

#include <iostream>
int main()
{
    A *x = new B();

   // Voert A::f() uit, want het gedeclareerde type van *x is A
   std::cout << x->f() << std::endl;

    // Voert B::g() uit, want het werkelijke (run-time) type van *x is B!
   std::cout << x->g() << std::endl;
}

[ Voor 3% gewijzigd door Soultaker op 28-06-2006 20:35 ]


  • writser
  • Registratie: Mei 2000
  • Laatst online: 10-02 20:24
No offence, maar lees eerst een goed boek over c++ en kom dan terug. Accelerated c++ (van Andrew Koenig and Barbara E. Moo) is een van de betere boeken om objectgeorienteerd programmeren te leren.

Onvoorstelbaar!


  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
writser schreef op woensdag 28 juni 2006 @ 20:37:
No offence, maar lees eerst een goed boek over c++ en kom dan terug. Accelerated c++ (van Andrew Koenig and Barbara E. Moo) is een van de betere boeken om objectgeorienteerd programmeren te leren.
Dat boek heb ik al lang, maar dit vind ik toch echt een pittig onderwerp hoor.
Soultaker schreef op woensdag 28 juni 2006 @ 20:34:
[...]

Hmm, een forward declaration zou ik het niet willen noemen. Het verschil tussen een virtual en een non-virtual method is dat bij de non-virtual method al tijdens het compileren, op basis van het type van de variabele, bepaald wordt welke methode aangeroepen wordt, terwijl dat bij een virtual method at runtime wordt bepaald, aan de hand van het feitelijke type van het object.

Nogal een ingewikkelde zin, dus een kort voorbeeld:
C++:
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 A {
public:
  int f() { return 1; }
  virtual int g() { return 2; }
};

class B : public A {
public:
  int f() { return 3; }
  int g() { return 4; }
  // Dit kan ook, en is equivalent:
  // virtual int g() { return 4; }
};

#include <iostream>
int main()
{
    A *x = new B();

   // Voert A::f() uit, want het gedeclareerde type van *x is A
   std::cout << x->f() << std::endl;

    // Voert B::g() uit, want het werkelijke (run-time) type van *x is B!
   std::cout << x->g() << std::endl;
}
Mooie uitleg :)
Maar ik twijfel nog over een paar dingen, met name dit:
C++:
1
A *x = new B();

x verwijst naar een plek in het geheugen waar de compiler een A classe gaat verwachten, maar je wijst naar een classe B.
Gaat dit programma niet helemaal over de zeik als je bijvoorbeeld met een array van A's gaat werken?

oprecht vertrouwen wordt nooit geschaad


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 15-02 21:33
Da's het hele idee van polymorfie in OOP: je kunt een B& converteren naar een A& als B een subklasse is van A. Vandaar dus dat je een B& (of B*) kunt geven waar een A& (of A*) verwacht wordt -- een B is simpelweg een A. Als dit abstract klinkt, vervang in het voertuig dan A door Voertuig en B door Auto, of A door Fruit en B door Appel ofzoiets. ;)

Ik weet niet wat je bedoelt met "over de zeik gaan als je met een array van A's werkt". Je kunt een array van A's (dus niet: een array van pointers naar A) inderdaad niet converteren naar een array van B's, maar waarom zou je dat ook willen?

Verder heeft writser wel een punt: als je dit allemaal voor het eerst hoort is het waarschijnlijk slim om een boek erbij te pakken (misschien Thinking in C++). Je kunt dit soort beslissingen gewoon niet nemen als je niet eens weet wat de mogelijkheden en beperkingen van de programmeertaal zijn.

[ Voor 38% gewijzigd door Soultaker op 28-06-2006 22:42 ]


  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
Het is niet dat ik dit de eerste keer tegenkom, maar het is wel nieuw voor mij om dit in te passen in bestaande code. Ik denk dat ik m'n bestaande code eens moet herzien om echt gebruik te kunnen maken van polymorfisme.

en voor de rest, I'm learning as I go ;)

oprecht vertrouwen wordt nooit geschaad


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 15-02 11:20
Atgast schreef op woensdag 28 juni 2006 @ 22:30:
Het is niet dat ik dit de eerste keer tegenkom, maar het is wel nieuw voor mij om dit in te passen in bestaande code. Ik denk dat ik m'n bestaande code eens moet herzien om echt gebruik te kunnen maken van polymorfisme.

en voor de rest, I'm learning as I go ;)
As do we all :)

Dit is en blijft het moeilijkste onderdeel van software maken: een goed ontwerp.

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.

Pagina: 1