Auteur Sujet: C++ - hiérarchie des fichiers  (Lu 9925 fois)

marc_geo

  • Newbie
  • *
  • Messages: 23
    • Voir le profil
C++ - hiérarchie des fichiers
« le: août 04, 2020, 11:05:04 pm »
Bonsoir à tous,

Je me suis lancé dans l'étude de l'utilisation des classes et objets pour programmer certaines choses. Les articles sur locoduino étant vraiment bien faits et ayant fait quelques petits exercices, j'ai bien intégré les principes de base.
Il y a juste une chose que je n'arrive pas à à réaliser, malgré les dizaines de tutos que j'ai suivis .... après deux jours je fatigue et je fais appel à l'équipe. Je m'explique:

J'ai un souci en terme de hiérarchie de fichiers. Les exemples, tutos et articles que l'on trouve conçoivent en général des exemples basés sur un fichier principal, main(), ou encore le fichier .iso pour l'arduino et son IDE. Quand on a une routine qui fonctionne, tous mes essais fonctionnent bien, pas de souci.

Pour l'arduino j'ai par habitude plus utiliser un système modulaire avec des fonctions pour chaque modules, découpé en plusieurs fichiers .cpp et fichiers entêtes .h et un dernier fichier .config.h contenant certaines variables globales comme par exemple les définitions des pin #define pin A0 par exemple.
Ce que je voudrais réaliser, c'est définir x sorties digitales pour allumer des lampes de décors, maison, routes ou autres, et qui seraient allumées en partie ou dans son ensemble selon des événements (nuits, mouvements aléatoires dans une maison, magasin, ...)

Pour ce faire j'ai crée pour l'essai une class avec un constructeur très simple, c'est un simple on ou off avec l'argument dune pin à introduire LampeMaison LampeMaison(pinLampeMaison).
Encore une fois, dans une routine principale, cela fonctionne sans problème.
Par contre, si je veux faire appel classe à cette via une fonction autre que la routine principale, par exemple un module nuit, nuit.cpp et nuit.h avec par exemple une fonction AllumageNuit(), là cela coince.
Comment parvient-on à rendre une classe utilisable dans une hiérachie de fichiers autres que le fichier principal en l'exportant, un peu comme une variable.

Est-ce possible ?, même si je crois que j'ai encore du mal à concevoir un programme dans son ensemble sous la forme d'objets,étant trop habitué au morcelage en système de modules et fonctions que l'on insère petit à petit un peu "selon la nécessité" du moment et de l'idée.

Merci d'avance et belle soirée.

Marc




marc_geo

  • Newbie
  • *
  • Messages: 23
    • Voir le profil
Re : C++ - hiérarchie des fichiers
« Réponse #1 le: août 06, 2020, 12:34:44 am »
Bonsoir à tous,

J'avance, j'avance ......  ;)

J'ai trouvé une façon de pouvoir utiliser une classe en dehors de la boucle principale avec "static".
Par contre, je ne sais pas si les pros de la communauté seront d'accord avec mon code :P

Quand l'un d'entre vous aura le temps d'y jeter un regard critique (sans les tomates svp :D)

Belle soirée
« Modifié: août 06, 2020, 12:39:54 am par marc_geo »

Pyk35

  • Full Member
  • ***
  • Messages: 110
    • Voir le profil
Re : C++ - hiérarchie des fichiers
« Réponse #2 le: août 06, 2020, 05:58:10 pm »
Bonjour Marc,

Je viens de jeter un coup d'oeil et je me permets de critiquer mais c'est toi qui l'a demandé.
Ou j'ai mal compris ton intention, ou il y a un problème C++. Pourquoi ton objet est static? Du coup tu perds une partie de l'intérêt de la programme orientée objet (je ne dis pas que static ne doit pas être utilisé mais dans cet exemple, je ne comprends pas).

Tu créés une classe dont le but de pouvoir faire un on/off sur 2 pin de ton arduino mais du coup tu utilises qu'un seul objet static mais ce n'est pas ça l'objet (sauf cas particulier).

Un classe c'est un modèle de données + des méthodes (des fonctions/procédures). Un objet c'est une structure donnée propre bâtie sur le modèle de données de la classe. Dans ton exemple, tu a prévu une variable membre qui contient le numéro de pin mais tu ne l'utilises jamais. C'est dommage ! Dans cet exemple, il faut initialiser autant d'objet qu'il y a de pin à piloter et ensuite tu n'as plus besoin de rappeler la pin puisqu'elle est mémorisée par l'objet.

Voici comment je ferais :

Pourquoi ne pas déclarer en global 2 objets (genre juste avant la fonction setup, en dehors de toute fonction) :
Sdigi digi1(3);
Sdigi digi2(4);

Tu modifies ta class pour :
Dans le .h:

Tu remplaces :
    void SdigiInit(byte a);
    void SdigiOn(byte a);
    void SdigiOff(byte a);
par
    void SdigiInit(byte a);
    void SdigiOn();
    void SdigiOff();

Dans le cpp,  tu modifies la fonction SdigiInit :

// Fonction qui demande le numéro de pin mais en facultatif car on a créé l'objet avec un constructeur qui a déjà mémorisé le numéro de pin !
void Sdigi::SdigiInit(byte a = 0)
{
  if(a != 0) m_numSdigi = a;  // Si tu amènes la paramètre facultatif a, c'est que tu veux changer la pin mémorisée, sinon tu utilises m_numSdigi
  pinMode(m_numSdigi, OUTPUT);
  digitalWrite(m_numSdigi, LOW);
}

et ensuite :
void Sdigi::SdigiOn()
{
  digitalWrite(m_numSdigi, HIGH);
}

void Sdigi::SdigiOff()
{
  digitalWrite(m_numSdigi, LOW);
}

Maintenant le fichier .ino :

void setup() {
  digi1.SdigiInit();
  digi2.SdigiInit();
}

La loop :

void loop() {

  // essai de la classe dans la boucle
    digi1.SdigiOn();
    delay(2000);
    digi1.SdigiOff();
    delay(2000);
 
    digi2.SdigiOn();
    delay(2000);
    digi2.SdigiOff();
    delay(2000);

  // essai de la classe via une fonction extérieure
  led_delay();
}
Pour la loop, ce n'est pas terrible, on pourrait faire mieux mais pour débuter ça ira car c'est un programme de test.

Globalement c'est plutôt bien codé, le code est propre et tu as bien appréhendé la programmation avec plusieurs fichiers ce qui peut toujours être une prise de tête.

Pour répondre à ta dernière question, oui évidemment que c'est possible mais cela peut vite être compliqué. Pour ma part, je ferai comme ceci :
o Je créé une classe de basse qui contiendrait toutes les propriétés communes ainsi que le fonction commune à tous tes types d'objet
o Je ferai des classes pas objet : lumière, chauffage, prise de courant, etc. qui héritrait de la classe de base. Attention on ne fait pas de classe pour le plaisir, il faut qu'il y ait des comportements différents selon tes objets sinon aucun intérêt, on reste sur la classe de base ou on fait une classe commune.
o Dans le .ino, je ferais un tableau de pointeur d'objet global sur la classe de base. Dans le setup, je ferai des new de tous mes objets selon le pointeur du tableau.
o Dans la loop, je parcours le tableau à la recherche de quelque chose à faire. Aucun delay, on boucle à donf sur tous les objets et surtout sur une fonction d'écouter d'un ordre : communication serial, surveillance de pin d'entrée (de boutons ?), réception d'un message CAN ou Ethernet, etc.)

Il faudrait donc travailler l'aspect polymorphisme et héritage pour arriver à ça. Ce n'est pas si difficile que ça mais le plus dur est d'avoir les idées claires avec ces notions. Après quand on code ce genre de truc, le code final ressemble rarement à l'idée qu'on en avait au début. On fait, refait, recode, remodèlise, et on arrive à la fin à un truc que l'on trouve sympa :)
J'espère t'avoir aidé.
A+
A+
Cédric

marc_geo

  • Newbie
  • *
  • Messages: 23
    • Voir le profil
Re : C++ - hiérarchie des fichiers
« Réponse #3 le: août 06, 2020, 10:09:29 pm »
Merci pour ta réponse Cédric :)

Citer
Pourquoi ton objet est static?

En fait c'est le seul moyen que j'ai trouvé de faire sortir en quelque sorte la classe et de la rendre universelle à tout autre fichier cpp que le ino principal.
En analysant tes conseils, je me rend compte que je travaille un peu à l'envers dans ma conception .....
C'est ce que j'écrivais dans mon premier message, j'ai un peu de mal à rentrer dans cette logique de pensée objet, mais je ne désespère pas d'y arriver en tatonnant.

if(a != 0) m_numSdigi = a;  // Si tu amènes la paramètre facultatif a, c'est que tu veux changer la pin mémorisée, sinon tu utilises m_numSdigi
Alors ça c'est génial ! Ca réduit mes deux constructeurs en un seul .... (j'ai encore du chemin à faire ...).

Pour le reste, les tableaux, je maitrise assez pour ce que je veux en faire, par contre je dois encore bosser la notion des pointeurs, car là j'ai pas encore tout capté.
Allez, un peu de pain sur la planche ... :D

Je tiendrai le sujet à jour avec mes avancées.

Encore merci et belle soirée.

Marc

« Modifié: août 06, 2020, 11:18:09 pm par marc_geo »

marc_geo

  • Newbie
  • *
  • Messages: 23
    • Voir le profil
Re : C++ - hiérarchie des fichiers
« Réponse #4 le: août 07, 2020, 12:40:50 am »
Bonsoir à tous,

Sur base des conseils de Cédric (que je remercie encore, cela m'a éclairé l'esprit sur pas mal de choses dans la philosophie objet), j'ai refait mon code.
J'y ai fait quelques changements, principalement pour cette condition if(a != 0) m_numSdigi = a;.
Je l'ai retirée de la fonctionSdigiInit() pour la placer directement dans le constructeur. J'ai rajouté une fonction ONOff plus des analogWrite.
Va falloir rendre tout ça accessible pour des fonctions hors boucle principale, mais là je dois encore étudier le domaine des pointeurs !

Dernière petite question philosophico-théorique par rapport à  l'accessibilité justement: sachant que je traite dans mon exemple des sorties digitales qui n'auront jamais , d'une part, qu'un état On ou Off, d'autre part, le même numéro de sortie sur l'arduino, est-ce tant une fausse route ou une erreur de conception que de placer la classe qui les traitent en "static", car c'est très simple à écrire, la méthode des pointeurs étant sans doute plus ardue à concevoir ?

Belle soirée

Marc
« Modifié: août 08, 2020, 12:07:32 pm par marc_geo »

Thierry

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 810
    • Voir le profil
Re : C++ - hiérarchie des fichiers
« Réponse #5 le: août 07, 2020, 02:40:29 pm »
Bonjour

Quel courage de se lancer dans le monde des objets, mais c'est une grande satisfaction lorsqu'on arrive à faire quelque chose qui marche...

Le rôle d'une classe statique est de fournir des comportement et des données communes à tout le monde.

Imaginons que l'on veuille modéliser un réseau et ses trains. Chaque train serait une instance d'une classe train, peut être dérivée en trainMarchandises et trainVoyageurs... Mais le réseau est seul et restera seul, inutile donc d'en faire un 'new'. Il vaut mieux lui donner l'attribut 'static' qui va en faire un objet unique, impossible à instancier. Plus simplement, une classe static est déjà un objet en soi, tandis qu'une classe non statique n'est pas un objet, mais un prototype d'objet. Le véritable objet 'physique' sera celui issu d'un 'new' ou d'une déclaration globale comme Cédric le propose.

L'autre rôle que l'on peut donner à une classe statique en détournant légèrement le concept, c'est de regrouper des fonctions et des données qui sont liées sous un nom commun  plutôt que de laisser des petites fonctions isolées à droite ou à gauche...

marc_geo

  • Newbie
  • *
  • Messages: 23
    • Voir le profil
Re : C++ - hiérarchie des fichiers
« Réponse #6 le: août 09, 2020, 09:56:55 pm »
Hello à tous,

Courage ou inconscience hahaha  ;D

Plus sérieusement, merci pour ton avis, je commence doucement à entrevoir un peu les principes.
Pour l'instant, je bosse des petits exercices sur les pointeurs, toujours des choses simples avec mes deux leds.
Je suis parvenu à utiliser ma classe hors routine principale dans une autre fonction.
Je ne sais pas si c'est la meilleure façon, mais en tout cas, ça compile sans souci et en plus ça fonctionne  ;)

Belle soirée

Edit:  J'ai corrigé quelques bugs. En fait la boucle finissait par stopper car je n'effaçais pas convenablement les pointeurs (il faut effacer le pointeur et surtout le lien).

Marc
« Modifié: août 11, 2020, 03:46:52 pm par marc_geo »