1

Hello,
Pour un essai de jeu j'aimerais gérer les objets (incluant les ennemis) sous forme de classes (C++).
En C j'avais fait très simple, une structure avec des membres qui étaient des pointeurs sur des fonctions (un handler sur la fonction gérant le personnage, un sur la fonction le dessinant, etc.).
Là j'aimerais essayer en me basant sur une classe de type Objet par exemple, qui aurait les propriétés communes à tous les objets. Ensuite je déclare une classe de type EnnemiX qui hériterait de la classe de base mais qui surchargerait les méthodes 'dessine' et 'gère' par exemple. Ca c'est ok, maintenant le problème c'est que j'aimerais stocker ça dans une liste d'objets, et qu'en la parcourant je puisse faire un truc du style:
Objet mesObjets[...];

for (i = 0; i < numberof(mesObjets); i++)
{
    mesObjets[i].dessine();
}

Vous voyez le style? Est-ce que vous pourriez m'aiguiller vers les concepts nécessaires pour réaliser ça svp? smile
Merci ^^
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

2

Objet *mesObjets[...];

mesObjets[n] = new Ennemi();

mesObjets|m] = new AutreObjet();

for(i = 0 ; i < numberof(mesObjets) ; i++)
{
  mesObjets[i]->dessine();
}
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

3

Hu? J'avais testé et il me semblait que ça ne marchait pas... j'ai dû me gourrer alors sorry
Par contre j'ai oublié de demander, mais les performances sont-elles équivalentes? Ou est-ce qu'il va devoir parcourir une lookup table pour trouver la fonction etc.?
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

4

Il va chopper le pointeur vers la méthode dans la vtable référencée par chaque instance d'objet, donc j'imagine que les performances sont comparables à ce que tu faisais avant.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

5

Hum en effet je viens de retester et ça ne fonctionne pas, je ne dois pas m'y prendre comme il faut. Si j'écris par exemple ceci:
class Objet
{
public:
	static bool loaded;

	Objet();

	static bool load();
	void handle();
	void draw();
};

void Objet::draw()		{
	oslPrintf_xy(0, 0, "OBJET");
}


class Piece : public Objet
{
public:
	Piece();

	static bool load();
	void handle();
	void draw();
};

void Piece::draw()		{
	oslPrintf_xy(0, 8, "PIECE");
	Objet::draw();
}


Ensuite si je fais:
Objet *objets[100];
objets[0] = new Piece;
objets[0]->draw();

Il m'affiche OBJET (il ne passe visiblement pas dans PIECE) sad
C'est normal?
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

6

il faut que tu déclares la méthode draw comme étant virtuelle pour qu'il se base sur le type de l'objet pointé par objets[0] (Piece) et non pas sur le type du tableau objets (Objet*) pour décider quelle méthode draw appeler
class Objet 
{ 
public: 
	static bool loaded; 
 
	Objet(); 
 
	static bool load(); 
	void handle(); 
	virtual void draw(); 
}; 
 
void Objet::draw()		{ 
	oslPrintf_xy(0, 0, "OBJET"); 
}
avatar

7

je suppose que dans le constructeur de Piece il faut aussi appeler le constructeur de Objet, mais je sais pas le faire en c++.

8

9

l'appel du constructeur implicite parent (le constructeur sans arguments) se fait automatiquement, mais si tu veux appeler le constructeur parent avec des arguments particulier faut faire comme ça :
Piece::Piece(int arg) : Objet(arg) {}


ah et tant qu'on en est à parler de méthodes virtuelles, pense aussi à déclarer tes destructeurs comme étant virtuels si tu ne veux pas avoir de mauvaises surprises grin
avatar

10

Merci beaucoup smile
Hum... pas mal de concepts nouveaux là. Mais c'est intéressant ^^
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

11

Brunni (./5) :
Hum en effet je viens de retester et ça ne fonctionne pas, je ne dois pas m'y prendre comme il faut. Si j'écris par exemple ceci:
class Objet
{
public:
	static bool loaded;

	Objet();

	static bool load();
	void handle();
	void draw();
};

void Objet::draw()		{
	oslPrintf_xy(0, 0, "OBJET");
}


class Piece : public Objet
{
public:
	Piece();

	static bool load();
	void handle();
	void draw();
};

void Piece::draw()		{
	oslPrintf_xy(0, 8, "PIECE");
	Objet::draw();
}

Ensuite si je fais:
Objet *objets[100];
objets[0] = new Piece;
objets[0]->draw();

Il m'affiche OBJET (il ne passe visiblement pas dans PIECE) sad
C'est normal?

C'est normal tu l'appel en tant qu'objet "OBJET" et pas en tant qu'objet PIECE
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

12

Brunni:
Tu peux aussi définir des méthodes purement virtuelles (c'est à dire sans implémentation), de cette manière:
class Objet 
{ 
public: 
	Objet(); 
	virtual void draw()=0; 
}; 
Mais du coup, pour instancier une classe dérivé il faut qu'elle absolument qu'elle implémente la méthode draw.

./11 à lire ton message, on croirait qu'il faut caster les objets pour pouvoir accéder aux bonne fonctions.

13

ben tu utilise une fonctionnalitée de l'hritage, a savoir que "Piece" est un type d'objet. Mais quand tu es dans ce cas, le code qui utilise "objet" ne sais pas que "piece" existe... et pour faire ce que tu veux faire il n'y a que ce qui a été posté plus haut qui peut t'aider, c'est a dire les onctions virtuelle, ou la ça va forcer la fonction utilisant les "objets" a s'interesser sur le type reel de celui-ci et de voir qu'il faut en fait executer Piece:: Draw et pas Objet:: Draw

(edit: fuck les smileys...)
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

14

Merci Jyaif c'est cool ça effectivement, les objets à la base n'ont pas de code, c'est juste un modèle, et c'est aux autres de les implémenter ^^
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

15

Il va chopper le pointeur vers la méthode dans la vtable référencée par chaque instance d'objet, donc j'imagine que les performances sont comparables à ce que tu faisais avant.

nib, et plus precisement, il y aura quand meme une petite difference, il y aura deux dereferencements de pointeurs (avec une vftable en C++) au lieu d'un seul (avec ta version C), mais point de vue taille, tu n'aura que sizeof(void*) octets de plus par objets en C++ contre sizeof(void*) * le nombre de pointeurs sur fonctions en C.
(un pointeur vers la vftable, et un autre pointeur dans la vftable vers la fonction)
Aze:
ah et tant qu'on en est à parler de méthodes virtuelles, pense aussi à déclarer tes destructeurs comme étant virtuels si tu ne veux pas avoir de mauvaises surprises grin

brunni> autre precision histoire que tu le fasses pas sans savoir pourquoi grin (ou que si une "mauvaise surprise" en rapport avec ca t'arrive tu ne te demande pas d'ou elle vient, ou que si t'as pas envie que ca se comporte comme ca, tu puisse quand meme ^^) : quand tu construis ta classe avec un new, ca sera forcement avec la classe la plus specialisee que tu veuille avoir (si tu veux un objet Piece, tu vas faire un "new Piece", pas un "new Objet", a priori trioui), donc lors de l'appel du constructeur, le compilateur peut savoir, au compile-time, suivant l'arbre d'heritage (qu'il connait de facon sure, vu qu'il connait le type exact: "Piece"), quelle liste de constructeurs appeler ("Objet(), Piece()").
par contre pour la destruction, vu que tu peux vouloir detruire une liste de pointeurs vers des base classes via une methode generique qui n'a pas connaissance des types specialises, si tu ne rends pas tes destructeurs virtuels, la destruction ne commencera qu'a partir du type visible lors de la destruction.
donc en gros, pour ton exemple d'au dessus, si tu fais des "new Piece()", que tu stockes ca dans une liste d'Objet*, et qu'apres tu delete chaque objet dans la liste, ca n'appellera que le destructeur d'Objet, pas le destructeur de Piece pour les objets qui sont effectivement des pieces...


hm aussi, si tu ne veux obliger les classes qui derivent de Objet a implementer certaines methodes, au lieu de definir des methodes vides dans Objet tu peux les rendre virtuelles pures:
genre ca:

virtual void draw() = 0;

au lieu de:

virtual void draw() {}

ca petera une erreur a la compilation si t'essaye d'instancier Objet ou une classe qui derive d'Objet mais qui n'a pas defini draw()... bref...
et dans Piece tu mets:

class Piece
{
	...

	virtual void draw() override
	{
		oslPrintf_xy(0, 8, "PIECE"); 
		Objet::draw(); 
	}
};


"override" est facultatif, mais ca fait juste gueuler visual si jamais tu change la methode dans la classe de base en oubliant de changer celle dans la classe derivee, sans override ca compilerait silencieusement, en supposant que la methode dans la classe derivee est soit une nouvelle methode, soit un overload de la methode de la classe de base, suivant la modification... la, avec override, ca te sort un truc dans les lignes de "draw did not override any base class method, bla bla..."

par contre je sais pas si override est portable, mais bon c'est pas genant, et c'est quand meme bien pratique de l'avoir quand tu dev sous visual... au pire tu fais un

#if !defined(_MSC_VER)
#define override
#endif

pour que ca passe quand c'est pas compile avec visual
avatar
HURRRR !

16

ah tiens je connaissais pas le mot clé override sous VC++, mais y'a ça dans quelques autres langages et c'est effectivement assez pratique happy
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

17

C'est carrément non-standard ce truc!

Le cas où la fonction a le même nom, mais une signature différente peut être détecté par g++ automatiquement, cf. -Woverloaded-virtual.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

18

Ça ne coute pas cher à ajouter, c'est facile de faire en sorte que ça ne pose aucun problème avec les compilateurs qui ne le gèrent pas (cf ./15), et c'est plus puissant qu'un gros switch qui affecte sans distinction toutes les méthodes, donc c'est tout bon.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

19

Et puis GCC contient un sacré nombre de fonctionnalités non standards, alors chacun est quitte.
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

20

Oui enfin s'il faut commencer a faire ce genre de bidouille on est pas sorti du cauchemar!

Sinon je vois que personne a cité le nom liskov alors qu'il me semble que c'est la base pour bien commencer a faire de l'objet. (google: liskov principle)

21

virtuel est il un concept de c++ ou de la POO en général?
il me semble qu'en java les méthodes sont toutes virtuelles non?
(pas de troll je demande juste un détail technique)

22

--
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

23

Je dirais que c'est un concept POO : le polymorphisme dynamique. en java en effet elles sont toutes virtuelles et il faut un mot clé pour les rendre non virtuelles. On a donc exactement le même concept qu'en c++

sinon j'ai pas très bien compris la fonction du mot clé override confus
avatar

24

Du C++. Enfin il y a des mecanismes similaires dans les autres languages de POO, mais il sont quand meme mieux foutu (et on ne parle pas de classes virtuelle)...
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

25

les classes virtuelles ça ne sert pas uniquement en cas d'héritage multiple ?
avatar

26

non.
L'héritage multiple est de plus a éviter le plus souvent possible!

27

aze (./25) :
les classes virtuelles ça ne sert pas uniquement en cas d'héritage multiple ?

Non les classes virtuelle se rapproche du concept d'Interface en java ou en Objective-C mais en plus bordelique
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

28

aze (./25) :
les classes virtuelles ça ne sert pas uniquement en cas d'héritage multiple ?
JackosKing (./26) :
non.
Euh si ?
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

29

Heu non, et heureusement !
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

30

La notion d'héritage est une notion de substitution (sauf heritage d'implementation, mais c'est a éviter):
http://en.wikipedia.org/wiki/Liskov_substitution_principle

Une classe virtuelle pure est une classe pour faire une normalisation d'interface, elle est utilisée dans énormément de design patterns dont le plus important:
http://www.design-up.com/articles/design/principesoo/dip.html