1200

ouais, bande de nuls !
(sauf pen^2)
avatar

1201

(J'ai droit à un bon point ?)

1202

Folco (./1180) :
entry[ID_truc].ptr
Sasume (./1185) :
Hm, pourquoi y aurait-il un cast ? entry peut être une liste de Receive *, non ?

Exact, j'avais pensé à en faire une liste de mes objets considérés en tant que tels (ie dérivant de Receive et d'une autre classe genre icone ou sprite). MAis le polymorphisme me permet d'enregistrer l'adresse d'un objet de type Receive "pur", t'as raison. top
Sasume (./1185) :
Et oui, ça marcherait très bien. Tu peux même faire de ta classe Communication un singleton, ça t’évitera d’avoir à faire ta bidouille en début d’exécution.

Je vais regarder pour le singleton, j'ai vu ça passer dans mon bouquin (une combine avec une variable static empêchant la recréation de l'objet si je me souviens bien)
Tu parles de quelle bidouille au fait ? Le fait d'instancier une première fois un objet Communication ?
GoldenCrystal (./1186) :
Sinon Folco, est-ce que tu as vraiment besoin d'un mécanisme si sophistiqué dans ton projet ? Tu as vraiment des messages susceptibles d'être traités par plus d'un objet par émission ?

J'en sais rien grin Mais c'est le seul truc intelligent que j'ai trouvé pour tous les problèmes de mon jeu qui me sont passés par la tête.
GoldenCrystal (./1186) :
Tu as des exemples des messages que tu voudrais transmettre, à titre d'info ?

Voilà. Je peux vouloir dire : "ajoute cette unité (n° tant) à cette armée" + "déduis le prix de l'unité du portefeuille du joueur" + "mets à jour la liste d'icones des unités dans le menu".
Tout ça suite à un seul clic. Le problème, c'est qu'un tel message s'adresse à plusieurs objets... : objet Module pour rajouter une icone à la liste du module, objet Joueur->Portefeuille pour le fric, objet Joueur->Armée etc...
Donc 3 messages à propager, sachant que je ne gérais pas une pile de message mais un seul message (j'ai pensé à faire une pile, mais c'est très couteux de parcourir une pile pour chaque objet, surtout que sur l'ensemble, très peu auront un message à leur intention). Et mon Message était fortement typé : transmission de deux int + 1 pointeur. Génial, mais c'est hyper limitatif.
Là, l'avantage est que je peux faire une sorte de protocole (je sais pas comment appeler ça) :
- je vais t'envoyer deux pointeurs sur des objets dont tu sais quoi faire
- ok (je prépare ma liste)
- en v'là un
- et voilà, fini

Et il me suffit de surcharger sendMessage() et receiveMessage() dans la classe dérivée pour envoyer tous les types que je veux (chaque objet devant implémenter ses versions spécialisées dont il sait qu'il aura besoin).

Vu de loin, ça me parait souple, performant et surtout simple à utiliser : juste des sendMessage() à écrire pour les émetteurs, et des receiveMessage() pour les récepteurs. Il y a probablement mieux pour mon cas, mais c'est la seule idée de ce genre qui me soit venue.
GoldenCrystal (./1186) :
(Et oui, c'est un bon modèle, je me demande juste si c'est adapté à ce que tu veux faire)

(alors là, je suis content, je comprends l'utilité de l'héritage multiple par besoin, j'aime apprendre comme ça boing (ben oui, j'en avais jamais fait encore grin))
Kevin Kofler (./1188) :
Et voilà, tu viens de réinventer un système de signaux et de slots (en moins bien tongue.gif ).

Je sais très bien que Qt propose ça, mais je m'en fous, j'ai voulu trouver un système bien fait. Et tu sais très bien que je le sais, ce n'est pas ton premier post à ce sujet tongue
Ce qui aurait été intéressant, c'est de savoir ce que fait Qt de mieux et qui serait susceptible de m'intéresser, là oui je suis preneur cheeky

1203

Folco (./1202) :
Tu parles de quelle bidouille au fait ? Le fait d'instancier une première fois un objet Communication ?
Oui, instancier l’objet au début et le passer ensuite en paramètre du constructeur de chaque objet. Ton code sera clairement plus agréable avec un singleton pour la classe Communication.
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. »

1204

aze (./1200) :
ouais, bande de nuls ! (sauf pen^2)
Hé mais heu sad C'est de ça dont je te parlais dans ./1158 et ./1182 smile
Ce n'était pas très dur à trouver, mais Pen^2 t'a tout dit tsss
avatar

1205

Sasume (./1203) :
Oui, instancier l’objet au début et le passer ensuite en paramètre du constructeur de chaque objet. Ton code sera clairement plus agréable avec un singleton pour la classe Communication.

Et ça reste parfaitement propre, académique toussa de procéder ainsi ? Je pense que oui, mais... J'ai toujours réussi à faire mes programmes C/C++ (ok ça va pas loin) sans variable globale, là je vais pas y couper grin

Mais t'as raison, si je fais ça, ça sera bien plus propre top

1206

Hmm ouais bon, j'aurai (donc) tendance à penser que le système de messages n'est pas adapté à ce que tu veux faire. tongue
(Je détaillerai plus tard, si personne ne le fait avant moi, mais pour l'instant j'ai pas trop la tête à ça.)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

1207

Oui, tu utiliseras effectivement une variable globale eek
Mais c’est un peu normal car chaque classe a besoin d’utiliser le service de communication. C’est comme si ça faisait partie de leur environnement. Inutile de s’emmerder à stocker une référence vers l’objet Communication dans chaque objet… Et puis ta variable globale ne sera pas si dégueulasse dans le sens où elle sera protégée par un scope : tu écriras quelque chose du genre Communication::send(truc).
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. »

1208

Folco (./1202) :
Ce qui aurait été intéressant, c'est de savoir ce que fait Qt de mieux et qui serait susceptible de m'intéresser, là oui je suis preneur cheeky

[ul][li]Les signaux peuvent avoir des arguments, et les slots recevoir les arguments correspondants (ou aucun ou seulement les premiers, il ne doit pas obligatoirement récupérer tous les arguments, on peut connecter par exemple un signal (int, double) à un slot (int) ou (void)). Dans ton système de messagerie, tous les évènements/messages doivent avoir les mêmes arguments (tel que tu l'as écrit, aucun, donc je suppose que tu voudras au moins un void *userdata en pratique!), tu es obligé d'écrire du code en plus pour passer des paramètres arbitraires.[/li][li]Les types sont vérifiés automatiquement par Qt, tu ne peux pas avoir un slot qui essaie de récupérer un int quand on lui a passé un double, alors qu'avec un void * générique, ça peut se produire.[/li][li]Tu peux placer un signal dans la queue des évènements, ce qui permet aussi d'envoyer des signaux d'un thread à un autre. (Mais à l'intérieur d'un seul et même thread, l'appel est immédiat par défaut.)[/li][li]Les slots sont appelés par nom, alors que toi, tu dois te taper un switch pour savoir quel genre de message tu as reçu.[/li][/ul]
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é

1209

est ce que je pourrais avoir un exemple *simple* avec deux classes écrites à la main, l'une contenant un signal et l'autre un slot, et non basées sur des widgets, et un exemple d'appel?

1210

./1208> C'est l'étape qmake qui fait ça? (connexion slots <-> signaux)
(en d'autres termes c'est implémentable soi-même sans préprocessing du code?)
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

1211

même question. En fait je crois que non, il faut moc et la macro Q_OBJECT, mais ma demande d'exemple concerne une classe "truc" avec un slot "toto" qui est appelée par une classe "chose" avec un signal "pwet". ça se passe comment? je dois écrire quoi?

1212

Kevin Kofler (./1208) :
Les signaux peuvent avoir des arguments, et les slots recevoir les arguments correspondants (ou aucun ou seulement les premiers, il ne doit pas obligatoirement récupérer tous les arguments, on peut connecter par exemple un signal (int, double) à un slot (int) ou (void)).

Idem pour moi (avec la surdéfinition et les arguments par défaut tongue)
Kevin Kofler (./1208) :
je suppose que tu voudras au moins un void *userdata en pratique

Non, trop risqué, pas propre toussa.
Kevin Kofler (./1208) :
tu es obligé d'écrire du code en plus pour passer des paramètres arbitraires.

Un proto grin
Kevin Kofler (./1208) :
Les types sont vérifiés automatiquement par Qt, tu ne peux pas avoir un slot qui essaie de récupérer un int quand on lui a passé un double, alors qu'avec un void * générique, ça peut se produire.

Moi c'est g++ qui vérifie grin
Kevin Kofler (./1208) :
Tu peux placer un signal dans la queue des évènements, ce qui permet aussi d'envoyer des signaux d'un thread à un autre. (Mais à l'intérieur d'un seul et même thread, l'appel est immédiat par défaut.)

C'est sûr que c'est bien, mais j'en ai pas besoin.
Kevin Kofler (./1208) :
Les slots sont appelés par nom, alors que toi, tu dois te taper un switch pour savoir quel genre de message tu as reçu.

Ben oué... personne ne trafique mon code dans mon dos au moins tongue

1213

squalyl (./1209) :
est ce que je pourrais avoir un exemple *simple* avec deux classes écrites à la main, l'une contenant un signal et l'autre un slot, et non basées sur des widgets, et un exemple d'appel?

class1.h:
#include <QObject>

class Class1 : public QObject {
  Q_OBJECT
  public:
    Class1(QObject *parent = 0) : QObject(parent) {}
    void foo(void);
  signals:
    void signal1(int x);
};


class1.cpp:
#include "class1.h"

void Class1::foo(void)
{
  emit signal1(123);
}


class2.h:
#include <QObject>

class Class2 : public QObject {
  Q_OBJECT
  public:
    Class2(QObject *parent = 0) : QObject(parent) {}
  public slots:
    void slot1(int x);
};


class2.cpp:
#include "class2.h"

void Class2::slot1(int x)
{
  Q_UNUSED(x);
}


main.cpp:
#include "class1.h"
#include "class2.h"
#include <QCoreApplication>

int main(int argc, char **argv)
{
  QCoreApplication *app = new QCoreApplication(argc, argv);
  Class1 *obj1 = new Class1();
  Class2 *obj2 = new Class2();
  obj2->connect(obj1, SIGNAL(signal1(int)), SLOT(slot1(int)));
  obj1->foo();
  delete obj1;
  delete obj2;
  delete app;
  return 0;
}
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é

1214

J'aime bien Qt qui offre au C++ ce qui lui manque le plus par rapport a Java : une bibliothèque assez complète et cross-plateforme.

Par contre, je n'apprécie pas du tout leur système de signaux/slots qui obligent a passer par un générateur de code. Du coup on se retrouve a utiliser de faux mot clés C++. C'est vraiment dommage qu'ils n'aient pas choisi un système qui ne casse pas la grammaire du C++, il me semble qu'il existe pourtant bien des bibliothèque qui font cela.
avatar

1215

Bof, moi ça ne me gêne pas qu’ils ajoutent un pseudo surcouche à C++ (mots-clés signals, slots, emit, etc.).
Comment fait Boost pour parvenir au même résultat ?
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. »

1216

Je ne l'ai jamais utilisé mais d'après ce que j'en ai lu, il ne modifie pas la grammaire du C++, et n'oblige pas à passer par un générateur de code.
Et il me semble que c'est également le cas des autres bibliothèques de signal/slots
avatar

1217

template

1218

./1213> merci happy
le QCoreApplication est indispensable?

1219

Qt ne change pas la grammaire du C++, les .cpp sont compilés tels quels, sans préprocessage. Le MOC crée juste un fichier .cpp de plus avec les choses automatiquement générées.

signals est un #define pour protected, emit est un #define pour rien, le MOC génère une fonction protégée qui s'occupe d'émettre le signal, l'emit n'est qu'un appel à cette fonction.

Et slots est aussi un #define pour rien, le MOC s'occupe de générer du code qui permet de connecter un signal à ce slot, à part ça, ça fonctionne comme une fonction quelconque. (D'ailleurs, un slot peut aussi être virtuel ou non et public, protégé ou privé.)
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é

1220

squalyl (./1218) :
le QCoreApplication est indispensable?

Je ne suis pas sûr si c'est nécessaire ici, mais en règle générale, un programme Qt doit toujours construire une QCoreApplication ou une classe dérivée (QApplication, KApplication).
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é

1221

"je ne suis pas sûr que ce soit nécessaire", subjonctif parce que comme tu dis, on n'est pas sûr cheeky

Sasume, pourquoi voudrais-tu que je fasse un singleton ? Si la portée de l'objet est globale, et que chaque objet a le droit de connaitre la messagerie, pourquoi ne pas en faire simplement une variable globale de cet objet ? Ici, ça me semble tout à fait indiqué comme utilisation.

Bon, je dis ça aussi parce que je sais pas quoi en foutre de cette classe singleton, je comprends pas le principe de fonctionnement grin
class Singleton
{
private: 
  static Singleton _instance;
 
  Singleton() {}
  ~Singleton() {} 
  Singleton(const Singleton &);             // intentionally undefined
  Singleton & operator=(const Singleton &); // intentionally undefined
 
 
public:
  static Singleton &getInstance();
};
 
// Source file (.cpp)
//
// Static member initialization. 
//
Singleton Singleton::_instance;
 
Singleton &Singleton::getInstance()
{
  return _instance;
}

Je comprends pas comment s'initialise l'objet, ni comment ça s'utilise concrètement. Faut toujours appeler getInstance() pour avoir un objet (ou une référence sur l'objet) ? C'est chiant ça, en quoi c'est plus propre que ma solution ? grin

1222

Par mmsg svp embarrassed ©

C'est quoi qui pose problème ? L'idée est de rendre tous les constructeurs privés pour être sûr de garder le contrôle sur le nombre d'instances en circulation.
Folco (./1221) :
C'est chiant ça

Ben oui, enfin, non, c'est une contrainte, certes, mais c'est là tout l'intérêt justement grin

1223

C'est ça qui instancie l'attribut privé _instance. Il fait appel au constructeur sans argument de Singleton.
Folco (./1221) :
Singleton Singleton::_instance;


Disons que tu as un argument dans ton constructeur :
class Singleton{
private:
...
Singleton( std::string s ) {...tu fais qq chose avec s} 
...
};
Tu devrais initialiser ton singleton avec un truc du genre :
Singleton Singleton::_instance("le son ne fonctionnait pas sous Fedora Core, mais il parait que maintenant c'est réparé :o");

1224

ce que je ne comprends pas, c'est ce qui va m'empêcher d'écrire
Singleton Plouf;
Singleton Plaf;
et donc d'avoir deux objets...

1225

Facile : ton constructeur est privé, tu ne peux donc pas l'appeler depuis l'extérieur de la classe. (HS : C'est pratique aussi de rendre le constructeur par copie privé si on sait que celui par défaut va poser problème et qu'on ne veut pas s'emmerder à en implémenter un correct alors qu'on n'en a pas besoin)


EDIT : OK, je l'avais oublié dans mon exemple du ./1223, dsl si c'est ça qui t'a troublé.

1226

Folco (./1224) :
Singleton Plouf; Singleton Plaf;

Évite les majuscules aux instances à mon avis wink

1227

Ça revient effectivement exactement au même d’avoir un singleton ou une variable globale, au niveau de l’utilisation. Mais le singleton te permet d’interdire l’instanciation de la classe, d’avoir un meilleur contrôle sur ce qui se passe.
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. »

1228

Merci pour vos explications. Non en fait, là où je coince, c'est comment instancier un objet (construire le singleton quoi) alors qu'on a explicitement dit qu'il n'avait pas de constructeur ?
D'après mon bouquin, on a juste le droit d'initialiser une variable static d'un objet, même si elle est privée. Mais encore faut-il que l'objet qui la contient soit instancié, non ? Et on fait ça comment ?

1229

Tu utilises une fonction membre statique.
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. »

1230

Ah, j'avais pas vu le static de la méthode... Donc d'après le code de ./1221, elle retourne la variable statique de l'objet (return _instance), qui est elle-même l'objet ? (static Singleton _instance)