Dans le .cpp : constructeur avec sous-class facultative

Bonjour,

Je suis entrain de faire un programme pour gérer des neopixels avec deux fonctions différentes (chaqu'une ça class). Selon la déclarations des pins_Neopixels et le nombre de pixels par fonction, j'utilise une ou l'autre des fonctions sur des bandeaux distinct ou sur le même bandeau.
Etant donner que pas mal de fonctions seront communes et aussi pour simplifier l'utilisation dans le <.ino>, j'aimerait faire une "class master" (une instance par bandeau) qui s'occupe de gérer les deux fonctions(class), si elles existent.

Ma question:
J'aimerais comprendre ce que fais ce constructeur dans le <.cpp> après les parenthèses

master::master(int valeurA, int valeurB) : sousClassA(valeurA), sousClassB(valeurB){
	//...
}

Est ce que si je fais comme ci-dessous le résultat est le même ?

master::master(int valeurA, int valeurB){
	sousClassA = slave1(valeurA);
	sousClassB = slave2(valeurB);
	//...
}

Le but étant de construire les class "slave" que si certaine conditions sont remplies.
Un peut comme ceci:

master::master(int valeurA, int valeurB){
	if (valeurA > 0){sousClassA = slave1(valeurA);}
	else {pasDeSousClassA = true;}
	if (valeurB > 0){sousClassB = slave2(valeurB);}
	else {pasDeSousClassB = true;}
	//...
}

slave1::slave1(int valA) {/*...*/}

slave2::slave2(int valB) {/*...*/}

Salutations à tous, bonne journée

Charles_9999
J'aimerais comprendre ce que fais ce constructeur dans le <.cpp> après les parenthèses

La syntaxe suivante

master::master(int valeurA, int valeurB) :
               sousClassA(valeurA), sousClassB(valeurB)
{
   //...
}

appelle dans l'ordre de définition le constructeur de "sousClassA" puis de "sousClassB" lors de l'appel de celui de "master" (cf. https://laefy.github.io/CPP_Learning/chapter2/3-constructor/)
Méthode qui est toujours plus efficace que de le faire comme indiqué plus loin

Maintenant, si l'utilisation des sous classes est sous condition, naturellement ne pas appliquer cette méthode :wink:

A suivre...

Si j'ai bien compris, la deuxième façons de faire n'est pas vraimant fauce, mais fait ramer un peux plus le compilateur ?

PS: @claudius01 merci pour la raiponce et le lien.

Salut.
Je me doutes bien que sousClassA et sousClassB sont des objets membres de master, mais J'aurais préféré que tu joignes le .h, pour voir, et mieux conseiller.
J'ai comme l'impression qu'une agrégation n'est pas ce qui est le plus adapté dans ton cas.

Dans l'idée de base non, ce serais des objets séparé.
le .h devrais resembler à ceci:

#ifndef _NAME_H
#define _NAME_H

class slave1 {
  public:
    // Constructeur
      slave1(int valA);
  private:
	int _valA;
};

class slave2 {
  public:
    // Constructeur
      slave2(int valB);
  private:
	int _valB;
};

class master {
  protected:
	slave1 _sousClassA;
	slave2 _sousClassB;
  public:
    // Constructeur
      master(int valeurA, int valeurB);
  private:
	bool pasDeSousClassA = false;
	bool pasDeSousClassB = false;
};
#endif

Après réflexion, je trouve que de mettre les class slave dans la class master serais mieux pour mon projet, mais ça fais pas mal de code à modifier. Pourrai-je le faire par pointeurs ?
Et j'aimerais quand même savoir si mon idée de base est réalisable ?

Si ça peut aider, je veux bien mettre le code de mon projet dans son état actuel, mais c'est très brouillon et j'y vais à taton, c'est sûrement plein d'erreurs.

.ino
  #define NBR_LEDS_LIGHTBAR     48
  #define NBR_LEDS_SECTIONS_MAX  16
  // #define BLUETOOTH_DEBUG       /*Includ le port bluetooth AOG_DEBUG_L-Bar pour le débugage*/

  #if NBR_LEDS_LIGHTBAR > 0
    #define PIXEL_START_LIGHT_BAR 10
    #define PIN_LIGHT_BAR          4
      // Option:
      #define Auto_Day_Night
  #endif
  #if NBR_LEDS_SECTIONS_MAX > 0
    #define NBR_LEDS_SECTIONS_MAX  10
    #define PIN_SECTIONS_BAR       5
      #if defined(PIN_LIGHT_BAR) && PIN_LIGHT_BAR != PIN_SECTIONS_BAR
        // Option:
        #define Auto_Day_Night_Scet_bar
      #endif
  #endif

  ////////////////// Librairie déclaration ////////////////////
    #ifdef BLUETOOTH_DEBUG
      #include <BluetoothSerial.h>
      BluetoothSerial SerialBT;
    #endif

    #if NBR_LEDS_LIGHTBAR > 0 || NBR_LEDS_SECTION_MAX > 0
      #include <Adafruit_NeoPixel.h>
      #include "AOG_NeoPixel.h"
      #include "AOG_NeoPixelsColors.h"

      AOG_NeoPixelsColors AOG_RGB;
      #if defined(PIN_LIGHT_BAR) && PIN_LIGHT_BAR >= 0
        #if defined(PIN_SECTIONS_BAR) && PIN_SECTIONS_BAR >= 0
          #if PIN_LIGHT_BAR != PIN_SECTIONS_BAR
          #define SEND_PIXELS_TYPE  4   // light-bar et sections-bar sur un ruban-neopixels différent
            //Adafruit_NeoPixel AOG_Pixels = Adafruit_NeoPixel(NBR_LEDS_LIGHTBAR + PIXEL_START_LIGHT_BAR, PIN_LIGHT_BAR, NEO_GRB + NEO_KHZ800);
            //Adafruit_NeoPixel AOG_2_Pixels = Adafruit_NeoPixel(NBR_LEDS_SECTIONS_MAX + NBR_LEDS_SECTIONS_MAX, PIN_SECTIONS_BAR, NEO_GRB + NEO_KHZ800);
            //AOG_Light_bar lightBar = AOG_Light_bar(NBR_LEDS_LIGHTBAR, PIXEL_START_LIGHT_BAR, 0, 0, AOG_RGB, AOG_Pixels);
            //AOG_Light_bar lightBar2 = AOG_Light_bar(0, 0, NBR_LEDS_SECTIONS_MAX, NBR_LEDS_SECTIONS_MAX, AOG_RGB, AOG_2_Pixels);
      /* - Ancien constructeur - */
            Adafruit_NeoPixel AOG_2_Pixels = Adafruit_NeoPixel(NBR_LEDS_SECTIONS_MAX + NBR_LEDS_SECTIONS_MAX, PIN_SECTIONS_BAR, NEO_GRB + NEO_KHZ800);
            AOG_Light_bar lightBar2 = AOG_Light_bar(NBR_LEDS_SECTIONS_MAX, NBR_LEDS_SECTIONS_MAX, AOG_RGB, AOG_2_Pixels);
          #else
          #define SEND_PIXELS_TYPE  3   // light-bar et sections-bar sur le même ruban-neopixels
            //Adafruit_NeoPixel AOG_Pixels = Adafruit_NeoPixel(max(NBR_LEDS_LIGHTBAR + PIXEL_START_LIGHT_BAR, NBR_LEDS_SECTIONS_MAX + NBR_LEDS_SECTIONS_MAX), PIN_LIGHT_BAR, NEO_GRB + NEO_KHZ800);
            //AOG_Light_bar lightBar = AOG_Light_bar(NBR_LEDS_LIGHTBAR, PIXEL_START_LIGHT_BAR, NBR_LEDS_SECTIONS_MAX, NBR_LEDS_SECTIONS_MAX, AOG_RGB, AOG_Pixels);
          #endif
        #else
          #define SEND_PIXELS_TYPE  1   // seulement light-bar
            //Adafruit_NeoPixel AOG_Pixels = Adafruit_NeoPixel(NBR_LEDS_LIGHTBAR + PIXEL_START_LIGHT_BAR, PIN_LIGHT_BAR, NEO_GRB + NEO_KHZ800);
            //AOG_Light_bar lightBar = AOG_Light_bar(NBR_LEDS_LIGHTBAR, PIXEL_START_LIGHT_BAR, 0, 0, AOG_RGB, AOG_Pixels);
        #endif
      #elif defined(PIN_SECTIONS_BAR) && PIN_SECTIONS_BAR >= 0
        #define SEND_PIXELS_TYPE  2   // seulement sections-bar
            //Adafruit_NeoPixel AOG_2_Pixels = Adafruit_NeoPixel(NBR_LEDS_SECTIONS_MAX + NBR_LEDS_SECTIONS_MAX, PIN_SECTIONS_BAR, NEO_GRB + NEO_KHZ800);
            //AOG_Light_bar lightBar2 = AOG_Light_bar(0, 0, NBR_LEDS_SECTIONS_MAX, NBR_LEDS_SECTIONS_MAX, AOG_RGB, AOG_2_Pixels);
      #endif
      /* - Ancien constructeur - */
            Adafruit_NeoPixel AOG_Pixels = Adafruit_NeoPixel(NBR_LEDS_LIGHTBAR + PIXEL_START_LIGHT_BAR, PIN_LIGHT_BAR, NEO_GRB + NEO_KHZ800);
            AOG_Light_bar lightBar = AOG_Light_bar(NBR_LEDS_LIGHTBAR, PIXEL_START_LIGHT_BAR, AOG_RGB, AOG_Pixels);
    #else
      #define SEND_PIXELS_TYPE  0
    #endif
    /* ==> exemple d'utilisation de [pixelsSendType] :
     * #if (pixelsSendType == 1 || pixelsSendType == 3 || pixelsSendType == 4) AOG_Light_bar.Refrech();
     * #if (pixelsSendType == 2 || pixelsSendType == 4) AOG_2_Light_bar.Refrech();
    */
  ////////////// END Librairie déclaration ////////////////////

  ////// light-bar variables //////////
      uint8_t nLbRefrech = 0;
      uint8_t helloAgIO[] = {0x80,0x81, 0x7f, 0xC7, 1, 0, 0x47 };
  // END light-bar variables //////////

  ////// AOG variables ////////////////
    //Comm checks
      uint32_t currentTime = millis();
      uint32_t lastTime = millis();
      uint8_t watchdogTimer = 0;     //make sure we are talking to AOG
      uint8_t serialResetTimer = 0;  //if serial buffer is getting full, empty it
    //Parsing PGN
      bool isPGNFound = false, isHeaderFound = false;
      uint8_t pgn = 0, dataLength = 0, idx = 0;
      int16_t tempHeader = 0;
      //uint8_t AOG_ED[] = { 0x80, 0x81, 0x7f, 0xED, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0xCC };

  // END AOG variables ////////////////

void setup() {

  Serial.begin(38400);

  #ifdef BLUETOOTH_DEBUG
  SerialBT.begin("AOG_DEBUG_L-Bar"); //Bluetooth device name
  #endif

  #if NBR_LEDS_LIGHTBAR > 0
  /*Réglage optionnels*/
    lightBar.SetLightBarMode(1);      // default   0  <Actuelement de 0 à 1>  ==> Mode d'affichage: 0) standardt || 1) un quart de point
    lightBar.SetCmParPixel(10);      // default: 8  ==> cm par *point afficher. *[en mode 1, les trois premier points sont des quarts de point]
    // lightBar.SetLightBarReverse(true); //default false  ==> inverser le sens d'affichage des points
    //lightBar.SetBrightness(60);       // default 120  <min 20 / max 255>    ==> luminosité des leds
    //lightBar.SetBrightnessNight(100); // default 40%  <min 10 / max 100>    ==> luminosité des leds la nuit [ en % de SetBrightness]
    //lightBar.SetIsDay(false);         // default true ==> éclairage en mode jour
    lightBar.SetNightNighting(true);  // default false  ==> point blanc aux extrémitée de la bar si "IsDay = false"
        /* Info: AOG_Pixels.Color( R, G, B ) >> return: uint32_t  >> fonction de la librerie: Adafruit_NeoPixel */
    // AOG_RGB.lBar1 = (AOG_Pixels.Color(5,200,5));   // définire la couleur des point à droite    (en mode 1 = quarts de point)
    // AOG_RGB.lBar2 = (AOG_Pixels.Color(200,5,5));   // définire la couleur des point à gauche    (en mode 1 = points entiers)
    // AOG_RGB.lBarCentre = (AOG_Pixels.Color(100,100,5)); // définire la couleur du point central
  #endif
} // END SETUP //////////////////////

void loop() {

  currentTime = millis();

  if (currentTime - lastTime >= nLbRefrech *29) {   // Interval entre les rafraichissements de la ligth-bar
    nLbRefrech++;
    #if SEND_PIXELS_TYPE == 1 || SEND_PIXELS_TYPE == 3 || SEND_PIXELS_TYPE == 4
      lightBar.Refrech();
    #endif
    #if SEND_PIXELS_TYPE == 2 || SEND_PIXELS_TYPE == 4
      lightBar2.Refrech();
      //test.print("Ne doit pas compiler");
    #endif
    //if (pixelsSendType == 2 || pixelsSendType == 4) AOG_2_Light_bar.Refrech();
    // #if NBR_LEDS_LIGHTBAR > 0
    // lightBar.Refrech();
    // #endif
  }

  //Loop triggers every 200 msec and sends back gyro heading, and roll, steer angle etc
  if (currentTime - lastTime >= 200) {
    lastTime = currentTime;
    nLbRefrech = 0;

    if (watchdogTimer++ > 250) watchdogTimer = 13;  // Pour éviter  qu'il boucle et recommance à zéro // "watchdogTimer++" ajoute 1 à watchdogTimer

    //clean out serial buffer to prevent buffer overflow
    if (serialResetTimer++ > 20) {
      while (Serial.available() > 0) Serial.read();
      serialResetTimer = 0;
      #if NBR_LEDS_LIGHTBAR > 0    //show life in AgIO   --> copier depuis : Autosteer_USBv5_0
        Serial.write(helloAgIO,sizeof(helloAgIO));
      #endif
    }
  }   //end of timed loop


  // Serial Receive
    //Do we have a match with 0x8081?
    if (Serial.available() > 4 && !isHeaderFound && !isPGNFound) {
      uint8_t temp = Serial.read();
      if (tempHeader == 0x80 && temp == 0x81) {
        isHeaderFound = true;
        tempHeader = 0;
      } else {
        tempHeader = temp;  //save for next time
        return;
      }
    }

    //Find Source, PGN, and Length
    if (Serial.available() > 2 && isHeaderFound && !isPGNFound) {
      Serial.read();  //The 7F or less
      pgn = Serial.read();
      dataLength = Serial.read();
      isPGNFound = true;
    }

    //The data package
    if (Serial.available() > dataLength && isHeaderFound && isPGNFound) {         
      // if (pgn == 239) {  // EF Machine Data
        // //reset watchdog
        // watchdogTimer = 0;
        // //Reset serial Watchdog
        // serialResetTimer = 0;
        // }
      // else if (pgn == 238)  //EE Machine Settings
      // else if (pgn == 236)  //EC Relay Pin Settings
      // else if (pgn == 254) {  // FE Machine
      if (pgn == 247) {  // Sections color
        uint8_t tempSectByte[9];
        for (int i = 0; i < 9; i++){
          tempSectByte[i] = (Serial.read();
        }
        // ==>> envoyer tempSectByte : sectbar.colors(tempSectByte, sizeof(tempSectByte))
      }
      #if NBR_LEDS_LIGHTBAR > 0
      //else if (pgn == 248) { } // F8 Light bar configue
      else if (pgn == 249) {  // F9 Light bar data
        lightBar.distance((int16_t)(Serial.read() << 8 | Serial.read()));

        #ifdef Auto_Day_Night
        { int8_t tempPhByte = Serial.read();
          if (tempPhByte == 2) lightBar.SetIsDay(false);
          else if (tempPhByte == 1) lightBar.SetIsDay(true);
          //SerialBT.print("IsDay = ");SerialBT.println(lightBar.GetIsDay(true));
        }
        #else
        Serial.read();
        #endif
        
        Serial.read();    //  read: crc
    } //END : (pgn == 249) F9 Light bar
    #endif

    //reset for next pgn sentence
    isHeaderFound = isPGNFound = false;
    pgn = dataLength = 0;
  }   // end Serial Receive

} // END LOOP ///////////////////////

================================================

AOG_NeoPixel.h
#ifndef AOG_NEOPIXEL_H
#define AOG_NEOPIXEL_H

//#define _Bluetooth_debug  /*Ajout le reseau bluetooth _AOG_DEBUG_L-Bar pour le debugage*/

#include <stdint.h>
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include "AOG_NeoPixelsColors.h"

#ifdef _Bluetooth_debug
  #include <BluetoothSerial.h>
  BluetoothSerial _SerialBT;
// Plus utile : class BluetoothSerial;    // Partage de class voir: https://forum.arduino.cc/t/inclure-liquidcrystal-dans-une-classe-perso/177782/5
#endif

class AOG_NeoPixelsColors;
class Adafruit_NeoPixel;

class AOG_Light_bar {
  protected:
    AOG_NeoPixelsColors& Z_AOG_RGB;
    Adafruit_NeoPixel& Z_AdaPixels;

  public:     // Constructeur :
      //AOG_Light_bar(AOG_NeoPixelsColors& AOG_RGB, Adafruit_NeoPixel& AdaPixels);
      AOG_Light_bar(uint8_t nbrPixels, uint16_t ignoreStartPixel, AOG_NeoPixelsColors& AOG_RGB, Adafruit_NeoPixel& AdaPixels);
   
  private:    // Fonction private:
      void _f_newBrightness();
      void _f_refrech();
      void _f_turnOnOff();
      void _f_showConnect(bool conected);
      bool _f_showMode();      
      int16_t _f_nbLevelMode(int16_t distance); //Avec REVERSELIGHTBAR!
  ///////////// A Ecrire ///////////////////////
      void _f_sendHelloF9 ();
      uint16_t _f_AOG_CK_A(uint8_t *Message);
  //////////// END à écrire //////////////////////
  
  public:    // Fonctions public:
      //void begin(bool testPixels);  
      //void beginNew(bool testPixels);  
      bool valeurs(uint8_t nbrPixels, uint16_t mmParLightbarPixel, bool lightBarON);
      void Refrech();
      void turnOn();
      void turnOff();
      void distancePlus(int16_t distanceLigne, bool isDay){SetIsDay(isDay); distance(distanceLigne);};
      void distance(int16_t distanceLigne);
    // Set / Get
      bool GetIsOff();
      bool GetIsOn();
      uint16_t GetDistanceLigne() const                 {return this->_distanceLineLast;}
      uint16_t GetLevelPixels()   const                 {return this->_nLevel;}
      void SetMmParPixel(uint16_t mmPixel);
      void SetCmParPixel(uint16_t cmPixel)              {SetMmParPixel(cmPixel * 10);}
      uint16_t GetMmParPixel()  const                   {return this->_lbMmPixel;}
      uint16_t GetCmParPixel()  const                   {return (this->_lbMmPixel + 4) / 10;}
      void SetIgnorePixel(uint8_t ignoreStartPixel);
      void SetDelayShutdown(uint16_t delayShutdown);
      uint16_t GetDelayShutdown()  const                {return this->_delayShutdown;}
      void SetBrightness(uint8_t brightnessPixels);
      uint16_t GetBrightness()  const                   {return this->_lbBrightness;}
      void SetIsDay(bool IsDay);
      bool GetIsDay()  const                            {return !this->_lbNight;}
      void SetNightNighting(bool nighting);
      void SetBrightnessNight(uint8_t brightnessPixelsNight); // % d'éclairage la nuit
      uint16_t GetBrightnessNight()  const              {return this->_brightnessNight;}
      void SetLightBarReverse(bool reverseLightBar);
      bool GetLightBarReverse() const                   {return this->_lbReverse;}
      void SetLightBarMode(uint8_t ModeLightBar);
      uint8_t GetLightBarMode();
  
  private:    // Variables private:
    uint32_t _lbOnOff_TimerTurne = millis();
    int16_t _distanceLine = -32123;
    int16_t _distanceLineLast = -32123;
    uint8_t _nbrPixels = 0;             // number pixel light-bar || Odd number dont use =0 (if = 0 Light-Bar disable)
    uint8_t _startPixels = 0;           // Pixel ignorés en début de bande
    uint8_t _centrePixel = 0;           //
    uint16_t _lbMmPixel = 80;           // 40 = 4cm (value between 1 and 255)
    uint8_t _lbBrightness = 120;        // brightness value between 0 and 255
    bool _brightnessChange = false;     //
    bool _lbNight = false;              // valeur si Neo_Phare_Pin non utilisé autrement voir ci-dessous
    bool _lbNighting = false;           // si activé remplace les pixels d'extrémités noir par du blanc-léger (pour voir la longueur de la bar dans la nuit) Combinable avec Neo_Phre_Pin.
    uint8_t _brightnessNight = 40;      // [en %]
    bool _lbReverse = false;            //bool ReverseLightBar = false;
    int8_t _lbModeShow = 1;             //
    int16_t _nLevel = -32666;
    uint16_t _delayShutdown = 751;      //[ms]  Temps avant la déactivation en cas de non réception de valeurs depuis AOG (tablette)
    uint16_t _delayRefrech = 106;
    uint32_t _lastDistanceTime = 0;
    uint32_t _lastShowTime = 0;
    int8_t _lbStatus = -2;        // -2: pas de connection avec AOG || -1: AGO distance invalide || 0: start || 1: distance valide || -5: tourne à On || -6: tourne à Off || -7 Off
    int8_t _lbStatusLast = 0;
};

class AOG_Sect_bar {
  protected:
    AOG_NeoPixelsColors& Y_AOG_RGB;
    Adafruit_NeoPixel& Y_AdaPixels;

  public:
    // Constructeur
      AOG_Sect_bar(uint8_t Sections_nbr_Pixels, uint16_t Sections_Start_Pixel, AOG_NeoPixelsColors& AOG_RGB, Adafruit_NeoPixel& AdaPixels);
  private:
};

class AOG_Pixels {
  protected:
    //AOG_Light_bar _Light_bar;
    //AOG_Sect_bar _Sect_bar;
    //AOG_NeoPixelsColors& _AOG_RGB;
    //Adafruit_NeoPixel& _AdaPixels;

  public:     // Constructeur :
      AOG_Pixels(uint8_t Light_bar_nbr_Pixels, uint16_t Light_bar_Start_Pixel, uint8_t Sections_nbr_Pixels, uint16_t Sections_Start_Pixel, AOG_NeoPixelsColors& AOG_RGB, Adafruit_NeoPixel& AdaPixels){};
};
#endif

================================================

AOG_NeoPixel.cpp
#include <stdint.h>
#include "AOG_NeoPixel.h"
#include <Adafruit_NeoPixel.h>

#ifdef _Bluetooth_debug
  #include <BluetoothSerial.h>
#endif

//Constructeur  // Partage de class voir: https://forum.arduino.cc/t/inclure-liquidcrystal-dans-une-classe-perso/177782/5
  AOG_Light_bar::AOG_Light_bar(uint8_t nbrPixels, uint16_t ignoreStartPixel, AOG_NeoPixelsColors& AOG_RGB, Adafruit_NeoPixel& AdaPixels) : Z_AOG_RGB(AOG_RGB), Z_AdaPixels(AdaPixels) {
    if (nbrPixels>1) {
      this->_nbrPixels = nbrPixels-1;
      this->_startPixels = ignoreStartPixel;

      this->_centrePixel = this->_startPixels + nbrPixels/2;
      this->_lbStatus = 0; this->_lbStatusLast = -3;    //this->_lbOn_Off = true;
    }
    #ifdef _Bluetooth_debug
    _SerialBT.begin("_AOG_DEBUG_L-Bar"); //Bluetooth device name
    #endif

    Z_AdaPixels.begin();
    delay(50);
    Z_AdaPixels.clear();
    Z_AdaPixels.show();
  }
  
  AOG_Sect_bar::AOG_Sect_bar(uint8_t Sections_nbr_Pixels, uint16_t Sections_Start_Pixel, AOG_NeoPixelsColors& AOG_RGB, Adafruit_NeoPixel& AdaPixels) : Y_AOG_RGB(AOG_RGB), Y_AdaPixels(AdaPixels) {
  }
  /*AOG_Pixels::AOG_Pixels(uint8_t Light_bar_nbr_Pixels, uint16_t Light_bar_Start_Pixel, uint8_t Sections_nbr_Pixels, uint16_t Sections_Start_Pixel, AOG_NeoPixelsColors& AOG_RGB, Adafruit_NeoPixel& AdaPixels)
                            :  _Light_bar(Light_bar_nbr_Pixels, Light_bar_Start_Pixel, AOG_RGB, AdaPixels),
                              _Sect_bar(Sections_nbr_Pixels, Sections_Start_Pixel, AOG_RGB, AdaPixels) {
    // Ou :                            
    *  {
      if (Light_bar_nbr_Pixels > 0) {
        this->_Light_bar = AOG_Light_bar(Light_bar_nbr_Pixels, Light_bar_Start_Pixel, AOG_RGB, AdaPixels);
      }
      else {
        // Il n'y a pas de light-bar
      }
      if (Sections_nbr_Pixels > 0) {
        if (Light_bar_nbr_Pixels + Light_bar_Start_Pixel < Sections_Start_Pixel || Sections_nbr_Pixels + Sections_Start_Pixel < Light_bar_Start_Pixel){
          this->_Sect_bar = AOG_Sect_bar(Sections_nbr_Pixels, Sections_Start_Pixel, AOG_RGB, AdaPixels);
      }
      else {
        // Il n'y a pas de section-bar
      }
    *
  }*/

//Méthode redéfinition de valeurs
  // void AOG_Light_bar::begin(bool testPixels){
  //   #ifdef _Bluetooth_debug
  //   _SerialBT.begin("_AOG_DEBUG_L-Bar"); //Bluetooth device name
  //   #endif

  //   _AdaPixels.updateLength(this->_startPixels + this->_nbrPixels);  // Adafruit_NeoPixel ->void updateLength(uint16_t n);
  //   _AdaPixels.updateType(NEO_GRB + NEO_KHZ800);                     // Adafruit_NeoPixel ->void updateType(neoPixelType t);
  //   _AdaPixels.begin();
  //   delay(50);
  //   _f_newBrightness();
  //   delay(20);
  //   _AdaPixels.clear();
  //   delay(20);
  //   if (this->_lbStatus > -5) {  // if (this->_lbOn_Off) {
  //     if (!testPixels) {
  //       this->_lbStatusLast = this->_lbStatus; this->_lbStatus = -7;  //this->_lbOn_Off = false;
  //       _f_turnOnOff();
  //       this->_lbOnOff_TimerTurne += 250;
  //     }
  //     _AdaPixels.show();
  //     delay(20);
  //   }
  //   if (testPixels) {
  //     //TestPixels();
  //   }
  // }
  
  void AOG_Light_bar::Refrech() {
    _f_refrech();
  }

  void AOG_Light_bar::SetIgnorePixel(uint8_t ignoreStartPixel) {
    if (this->_startPixels != ignoreStartPixel) {
      this->_startPixels = ignoreStartPixel;
      this->_centrePixel = this->_nbrPixels/2 + ignoreStartPixel;
    }
  }

  void AOG_Light_bar::SetMmParPixel(uint16_t mmPixel) {
    if (this->_lbMmPixel != mmPixel) {
      this->_lbMmPixel = mmPixel;
      this->_lbStatusLast = -3;
    }
  }

  //void  AOG_Light_bar::SetCmParPixel(uint16_t cmPixel) {SetmmParPixel(cmPixel * 10);}

  void AOG_Light_bar::SetDelayShutdown(uint16_t delayShutdown) {
    this->_delayShutdown = delayShutdown;
  }

  void AOG_Light_bar::SetBrightness(uint8_t brightnessPixels) {
    // if (brightnessPixels > 10) {
    //   LIGHTBARONOFF(false);
    // } 
    // else {
    //   if (_lbOnOff == false) LIGHTBARONOFF(false);
    // ...}
    if (brightnessPixels < 10) brightnessPixels = 10;
    if (abs(this->_lbBrightness - brightnessPixels) > 5) {
      this->_lbBrightness = brightnessPixels;
      this->_brightnessChange = true;
    }
  }

  void AOG_Light_bar::SetBrightnessNight(uint8_t brightnessPixelsNight) {
    uint8_t tempN = brightnessPixelsNight;
    if (brightnessPixelsNight < 10) tempN = 10;           // % minimum
    else if (brightnessPixelsNight > 100) tempN = 100;    // % maximum
    this->_brightnessNight = tempN;
    this->_brightnessChange = true;
  }

  void AOG_Light_bar::SetIsDay(bool IsDay) {
    if (!IsDay != this->_lbNight) {
      this->_lbNight = !IsDay;
      this->_brightnessChange = true;
    }
  }

  void AOG_Light_bar::SetNightNighting(bool nighting) {
    if (this->_lbNighting != nighting){
      this->_lbNighting = nighting;
      this->_brightnessChange = true;
    }
  }

  void AOG_Light_bar::SetLightBarReverse(bool reverseLightBar) {
    if (this->_lbReverse != reverseLightBar) {
      this->_lbReverse = reverseLightBar;
      this->_lbStatusLast = -3; //pour forcer le rafraîchissement de l'affichage
    }
  }

  void AOG_Light_bar::SetLightBarMode(uint8_t ModeLightBar) {
    if (this->_lbModeShow != ModeLightBar) {
      this->_lbModeShow = ModeLightBar;
      this->_lbStatusLast = -3; //pour forcer le rafraîchissement de l'affichage
    }
  }

  uint8_t AOG_Light_bar::GetLightBarMode() {
    if (this->_lbModeShow < 1) {return 0;}
    else {return this->_lbModeShow;}
  }

  void AOG_Light_bar::distance(int16_t distanceLigne){
    this->_lastDistanceTime = millis();
    int8_t tempLevel = this->_nLevel;
    _f_nbLevelMode(distanceLigne);
    
    this->_distanceLine = distanceLigne;

    if (distanceLigne < -30000) {
        this->_lbStatus = -2;
    }
    else if (distanceLigne > 30000) {
        this->_lbStatus = -1;
    }
    else {
      if (tempLevel != this->_nLevel || this->_lbStatusLast != 1) {
        this->_lbStatusLast = 0;
        this->_lbStatus = 1;
      }
    }
  }

  void AOG_Light_bar::_f_refrech() {
    uint32_t tempTime = millis();
    if (this->_brightnessChange) {
      _f_newBrightness();
      this->_lbStatusLast = -3; //pour forcer le rafraîchissement de l'affichage
    }

    if (this->_lbStatus <= -5) {   // if (!this->_lbOn_Off || this->_lbOnOff_Turne) {
      if (this->_lbStatus != -7) _f_turnOnOff();
      return;
    }  // END if(this->_lbOn_Off) 

    if (int64_t(tempTime - this->_lastDistanceTime) >= this->_delayShutdown) {
      this->_lbStatus = -2;
      this->_lbStatusLast = -3; //pour forcer le rafraîchissement de l'affichage
      this->_lastDistanceTime = tempTime + this->_delayShutdown; //Réinitier le compteur (2* delais pour éviter d'envoyer des message dans le vide)
      _f_sendHelloF9();
    }

    if (abs(int64_t(tempTime- this->_lastShowTime)) >= this->_delayRefrech) {
        this->_lbStatusLast = -3;
    }

    if (this->_lbStatusLast == -3) _f_nbLevelMode(this->_distanceLineLast);

    if (this->_lbStatus != this->_lbStatusLast && this->_lbStatus != 0) { // Si Old status et différent du status afficher les dels correspondant
      if (this->_lbStatus == -2) {
        _f_showConnect(false);
      }
      else if (this->_lbStatus == -1) {
        _f_showConnect(true);
      }
      else if (this->_lbStatus == 1){ 
        _f_showMode();
      }
      else {    //Status inconnu !!!
        _f_showConnect(false);
        this->_lbStatus = 0;
      }
      this->_lastShowTime = tempTime;
      if (this->_lbStatusLast == -3 && this->_lbStatus == 1) {this->_lbStatusLast = -4;}
      else {this->_lbStatusLast = this->_lbStatus;}
      this->_lbStatus = 0;
    }
  }

  int16_t AOG_Light_bar::_f_nbLevelMode(int16_t distance) {  //Avec REVERSELIGHTBAR!
    int16_t tempreponse = -127;

    if (abs(distance) > 31000) {
      this->_distanceLineLast = this->_distanceLine;
      this->_nLevel = distance;
      //_SerialBT.print("XXX ");_SerialBT.println(distance);
      return tempreponse;
    }
    
    int16_t tempError = distance;
    //if (this->_distanceLineLast < -29999 || this->_distanceLineLast > 29999) tempError = (distance + this->_distanceLineLast) / 2;
    //if (abs(_distanceLineLast) < 29999 || abs(tempError) < 29999) tempError = (distance + this->_distanceLineLast) / 2;
    this->_distanceLineLast = tempError;
    if(this->_lbReverse) tempError = tempError * -1;

    switch (this->_lbModeShow) {
      case 1:   // Mode == 1
        // élever la valeur pour l'arrondi_inf fait par l'arduino.
          if (tempError > this->_lbMmPixel * 0.9) {tempError += (int)(this->_lbMmPixel * 0.4);}
          else if (tempError > 0) {tempError += (int)(this->_lbMmPixel * 0.1);}
          else if (tempError < this->_lbMmPixel * -0.9) {tempError -= (int)(this->_lbMmPixel * 0.4);}
          else if (tempError < 0) {tempError -= (int)(this->_lbMmPixel * 0.1);}
        tempreponse = constrain((int8_t)(tempError / this->_lbMmPixel),-(this->_centrePixel - this->_startPixels -3), (this->_nbrPixels - (this->_centrePixel - this->_startPixels) -3));
        if (tempreponse < 0) { tempreponse = tempreponse - 3; } //Arondi Arduino: 0.99 = 0 <> -0.99 = 0 //Calcul les entiers à gauche
        else if (tempreponse > 0) { tempreponse = tempreponse + 3; }  //Calcul les entiers à droite
        else {tempreponse = (tempError * 4) / this->_lbMmPixel;} // calcul les trois premier quarts à gauche et à droite et le centre
        break;
      default:  // Mode == 0 <<Ou>> Mode == Non parametré
        // élever la valeur pour l'arrondi_inf fait par l'arduino.
          if (tempError > 0) {tempError += (int)(this->_lbMmPixel * 0.4);}
          else if (tempError < 0) {tempError -= (int)(this->_lbMmPixel * 0.4);}
        tempreponse = constrain((int8_t)(tempError / this->_lbMmPixel),-(this->_centrePixel - this->_startPixels), (this->_nbrPixels - (this->_centrePixel - this->_startPixels)));
        break;
    }
    //_SerialBT.print(distance); _SerialBT.print(" \t ");_SerialBT.println(tempreponse);
    this->_nLevel = tempreponse;
    return tempreponse;
  }

  void AOG_Light_bar::_f_showConnect(bool conected){
    uint32_t tempColor;
    if (!conected) {tempColor = Z_AOG_RGB.error;}
    else {tempColor = Z_AOG_RGB.green;}

    for (int i = this->_startPixels; i < this->_nbrPixels +1 + this->_startPixels; i++) {
      Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.black);
    }

    Z_AdaPixels.setPixelColor(this->_startPixels, tempColor);
    Z_AdaPixels.setPixelColor(this->_startPixels + this->_nbrPixels, tempColor);
    Z_AdaPixels.setPixelColor(this->_startPixels + this->_nbrPixels /3, tempColor);
    Z_AdaPixels.setPixelColor(this->_startPixels + this->_nbrPixels *2/3, tempColor);
  
    Z_AdaPixels.show();
    delay(20);  // 20ms pour laisser le temp dècrire les pixels en cas de changement de status
  }

  bool AOG_Light_bar::_f_showMode() {

    if (abs(this->_nLevel) > this->_nbrPixels / 2 + 1) {    // Test que la variable numérot de pixel correspond au nombre de pixels affichables
      this->_lbStatus = -3;
      return false;
    }
    
    int tempLevel = this->_nLevel;
    int tempN = this->_centrePixel + tempLevel;

    switch (this->_lbModeShow) {
      case 1:     //ModePixel == 1  "1/4"
        if (tempLevel <0) {
          for (int i = this->_startPixels; i < this->_nbrPixels + 1 + this->_startPixels; i++) {
            if (i < tempN || i > this->_centrePixel) {
              Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.black);
            }
            else if ( i < this->_centrePixel -3 ) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBar2);}
            else if (i == this->_centrePixel) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBarCentre);} 
            else {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBar1);}
          }
        }
        else if (tempLevel >0) {
          for (int i = this->_startPixels; i < this->_nbrPixels +1 + this->_startPixels; i++) {
            if (i > tempN || i < this->_centrePixel) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.black);}
            else if ( i > this->_centrePixel +3 ) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBar2);}
            else if (i == this->_centrePixel) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBarCentre);} 
            else {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBar1);}
          }
        }
        else {
          for (int i = this->_startPixels; i < this->_nbrPixels +1 + this->_startPixels; i++) {
            if (i == this->_centrePixel) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBarCentre);}
            else {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.black);}
          }
        }
        break;
      default:    //ModePixel == 0 (OU par défaut)
        if (tempLevel < 0) {
          for (int i = this->_startPixels; i < this->_nbrPixels +1 + this->_startPixels; i++) {
            if (i < tempN || i > this->_centrePixel) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.black);}
            else if (i >= tempN && i < this->_centrePixel) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBar1);}
            else {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBarCentre);}
          }
        } else if (tempLevel > 0) {
          for (int i = this->_startPixels; i < this->_nbrPixels +1 + this->_startPixels; i++) {
            if (i > tempN || i < this->_centrePixel) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.black);}
            else if (i <= tempN && i > this->_centrePixel) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBar2);}
            else {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBarCentre);}
          }
        } else {
          for (int i = this->_startPixels; i < this->_nbrPixels +1 + this->_startPixels; i++) {
            if (i < this->_centrePixel || i > this->_centrePixel) {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.black);}
            else {Z_AdaPixels.setPixelColor(i, Z_AOG_RGB.lBarCentre);}
          }
        }
        break;
    }

    if (this->_lbNight && this->_lbNighting) {    //Activer les leds d'éclairage "nighting"
              // _SerialBT.print(tempN);
      //if (_AdaPixels.getPixelColor(this->_startPixels) == _AOG_RGB.black) _AdaPixels.setPixelColor(this->_startPixels, _AOG_RGB.with_light);
      //if (_AdaPixels.getPixelColor(this->_startPixels + this->_nbrPixels) == _AOG_RGB.black) _AdaPixels.setPixelColor(this->_startPixels + this->_nbrPixels, _AOG_RGB.with_light);
      if (tempN > this->_startPixels) Z_AdaPixels.setPixelColor(this->_startPixels, Z_AOG_RGB.with_light);
      if (tempN < this->_startPixels + this->_nbrPixels) Z_AdaPixels.setPixelColor(this->_startPixels + this->_nbrPixels, Z_AOG_RGB.with_light);
    }
    // test pour distinguer le pixel "nLevelPixelMode"  
      //_AdaPixels.setPixelColor(tempN, 0, 0, 255);  //blue
      //_AdaPixels.setPixelColor(this->_centrePixel, _AOG_RGB.blue);
    
    Z_AdaPixels.show();
    return true;
  }

  void AOG_Light_bar::_f_newBrightness() {
    uint8_t tempBrightness = this->_lbBrightness;
    if (this->_lbNight) {
      tempBrightness = tempBrightness * this->_brightnessNight / 100;
    }
    Z_AdaPixels.setBrightness(tempBrightness);
    this->_brightnessChange = false;
  }

  void AOG_Light_bar::_f_turnOnOff() {
    uint32_t tempColor = 0;
        // -2: pas de connection avec AOG || -1: AGO distance invalide || 0: start || 1: distance valide || -5: tourne à On || -6: tourne à Off || -7 Off
    if (this->_lbStatus != -5 && this->_lbStatus != -6) {   // si elle n'est pas entrain de tourner
      this->_lbOnOff_TimerTurne = millis();
      Z_AdaPixels.setBrightness(30);
      if (this->_lbStatus != -7) {                          // si elle est à On
        this->_lbStatus != -6;                              // => tourne à Off
        tempColor = Z_AOG_RGB.red;
      } else {                                              //si elle est à Off
        this->_lbStatus != -5;                              // =>tourne à On
        tempColor = Z_AOG_RGB.green;
      }
    }
    else if (abs(int64_t(millis() - this->_lbOnOff_TimerTurne)) > 700) {  // si elle est entrain de tourner est que le timer est atteint
      if (this->_lbStatus == -6) {                          // si elle est à tourne à Off
        this->_lbStatus = -7;                              // => OFF
        tempColor = Z_AOG_RGB.black;
      }
      else {                                                // si elle est à tourne à On
        this->_brightnessChange = true;
        this->_lbStatus = this->_lbStatusLast;              // => On (dernier status utilisé)
        if (this->_lbStatus < -2) this->_lbStatus = 0;     // confirme le passage à On
        this->_lbStatusLast = -5;
      }
    }
    if (this->_lbStatus <= -5) {                          // si elle n'est pas à ON, gère la couleur
      for (int i = this->_startPixels; i < this->_startPixels + this->_nbrPixels + 1; i++) {
        Z_AdaPixels.setPixelColor(i, tempColor);
      } 
    }
    Z_AdaPixels.show();
  }

  void AOG_Light_bar::turnOn(){
    if (this->_lbStatus == -6) this->_lbStatus = -7;
    if (this->_lbStatus == -7) _f_turnOnOff();
  }

  void AOG_Light_bar::turnOff(){
    if (this->_lbStatus == -5) this->_lbStatus = 0;
    if (this->_lbStatus > -5) {
      this->_lbStatusLast = this->_lbStatus;
      _f_turnOnOff();
    }
  }

  bool AOG_Light_bar::GetIsOff(){
    if (this->_lbStatus == -7) return true;
    else return false;
  }

  bool AOG_Light_bar::GetIsOn(){
    if (this->_lbStatus > -5) return true;
    else return false;
  }

  void AOG_Light_bar::_f_sendHelloF9() {
    uint8_t AOG_SendF9[] = { 0x80, 0x81, 0x7f, 
      0xF9, // nom de fonction : 0xF8 = LightBar config | 0xF6 = SctionsLeds config
      2,
      2,  // 1 = Je n'ai pas de light-bar | 2 = J'informe AOG que j'ai une light-bar | autre = ne pas changer cet état
      0,  // 0 = simple | 238 = module configurable depuis AOG
      0x7C  // crc
    };    
    Serial.write(AOG_SendF9, sizeof(AOG_SendF9));
      //// AOG-Visual_studio:
          // private void Receive[ModulName]Port(byte[] Data) {
          //     if (Data[0] == 0x80 && Data[1] == 0x81 && Data[3] == 0xF9) {
          //         if (Data[5] == 1) imuLightBar = false;  else if (Data[5] == 2) imuLightBar = true;
          //     } else if (Data[0] == 0x80 && Data[1] == 0x81 && Data[3] == 0xF6) {
          //         if (Data[5] == 1) imuSectionsLeds = false;  else if (Data[5] == 2) imuSectionsLeds = true;
          //     }
          //     //...
          // }
        //// END AOG-Visual_studio:
  }

/// A écrire
  uint16_t AOG_Light_bar::_f_AOG_CK_A(uint8_t *pMessage) {  //add the checksum for AOG
      int16_t CK_A = 0;
      for (uint8_t i = 2; i < sizeof(pMessage) - 1; i++)
      {
          CK_A = (CK_A + pMessage[i]);
      }

      return CK_A;
  }

================================================

AOG_NeoPixelsColors.h
#ifndef AOG_NEOPIXELSCOLOR_H
#define AOG_NEOPIXELSCOLOR_H

//#include <Adafruit_NeoPixel.h>

class AOG_NeoPixelsColors {
  public:
    AOG_NeoPixelsColors() {
      red = (200 <<16) +( 0 <<8) + (0);    //pixels.Color( 200 , 0 , 0 );
        //red = Color( 200 , 0 , 0 );
      red_light = (80 <<16) +( 0 <<8) + (0);    //pixels.Color( 80 , 0 , 0 );
      green = (0 <<16) +( 200 <<8) + (0);    //pixels.Color( 0 , 200 , 0 );
      yellow = (170 <<16) +( 170 <<8) + (0);    //pixels.Color( 170 , 170 , 0 );
      yellow_light = (70 <<16) +( 70 <<8) + (0);    //pixels.Color( 70 , 70 , 0 );
      orange = (170 <<16) +( 68 <<8) + (0);    //pixels.Color( 170 , 68 , 0 ); //( 255 , 102 , 0 );
      blue = (0 <<16) +( 0 <<8) + (200);    //pixels.Color( 0 , 0 , 200 );
      black = 0;
      with_light = (30 <<16) +( 30 <<8) + (30);    //pixels.Color( 50 , 50 , 50 );
      error = (200 <<16) +( 10 <<8) + (20);
      test = (80 <<16) +( 80 <<8) + (80);
      lBar2 = (180 <<16) +( 0 <<8) + (50);    //pixels.Color( 180 , 102 , 0 );
      lBar1 = (50 <<16) +( 0 <<8) + (180);    //pixels.Color( 240 , 20 , 0 );
      lBarCentre = (0 <<16) +( 180 <<8) + (0);    //pixels.Color( 0 , 150 , 0 );
    };

      uint32_t red;
      uint32_t red_light;
      uint32_t green;
      uint32_t yellow;
      uint32_t yellow_light;
      uint32_t orange;
      uint32_t blue;
      uint32_t black = 0;
      uint32_t with_light;
      uint32_t error;
      uint32_t test;
      uint32_t lBar1;
      uint32_t lBar2;
      uint32_t lBarCentre;

  private:
    // copie depuis Adafruit_NeoPixel.h
      static uint32_t Color(uint8_t r, uint8_t g, uint8_t b) {
        return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
      };
      static uint32_t Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
        return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
      };
};
#endif

Salutations, bonne journée

On va mettre les choses au clair tout d'abord :
Dans ton code _sousClassA et _sousClassB ne sont pas des classes, ce sont des instances des classes slave1 et slave2.

C'est justement ce que j'allais te proposer, mais j'ai un peu peur que t'emmèles les pinceaux, surtout que C++ ne possède pas de garbage collector.
Dans l'idée :

// La déclaration de sousClassA devient : 
	slave1 *_sousClassA = 0;   // initialisé à ZERO, c'est important pour la suite
// L'instanciation devient : 
sousClassA = new slave1(valeurA);
// idem pour _sousClassB

Une fois que tu as instancié sousClassA ou sousClassB, tu n'as plus besoin de tes flags pasDeSousClassA et pasDeSousClassB, puisque si le pointeur sousClassA ou sousClassB n'est pas nul, cela veut dire que l'objet existe, donc cela simplifie.
Par contre il te faut un destructeur :

master::~master()
{
  if (sousClassA) {
    delete sousClassA;
  }
  if (sousClassB) {
    delete sousClassB;
  }
}

A chaque fois que tu as besoin de détruire un objet tu dois écrire :

    delete sousClassA;
    sousClassA = 0;
// ou
    delete sousClassB;
    sousClassB = 0;

Comme tu peux le voir les contraintes sont plus importantes. Si tu te loupes tu as vite fait de consommer de la mémoire.

Avec les pointeurs, cela semble plus logique que mon idée de base.

avec ce que j'ai compris, j'ai fait ce petit projet qui à l'air de fonctionner
Wokwi lien

Par contre pour le destructeur je vois pas quand je devrais l’utiliser !

Tu ne l'utilise pas explicitement.
Il est appelé automatiquement lorsque ton instance de classe master est détruite.
Si ton instance master est globale, le destructeur n'est jamais appelé.
Si ton instance master est locale à une fonction ou méthode, le destructeur est appelé en sortie de fonction ou méthode.
Si ton instance master est créée dynamiquement à l'aide de new(), le destructeur est appelé quand tu détruis l'instance à l'aide de delete().

Ok, pour le destructeur cette fois c’est clair.

Encore une chose, à la dernière ligne du setup() de mon exemple, étant donné que test2.sousClassB vaut 0, je m’attendais à une erreur avec la ligne :

Serial.println(test2.sousClassB->GetValeur());

Mais il m’imprime une valeur sortie du chapeau magique.

Si tu as le temps, pourrais-tu jeter un œil à mon exemple et me faire un retour de ce qui ne va pas.

Dans tous les cas, un grand merci pour m’avoir permis de faire un pas de plus dans le monde des objets.
Salutations, bonne journée

  Serial.println(test2.sousClassB->GetValeur());  // l'objet test2.sousClassB n'est pas déclarée

Alors que test2 est instancié ainsi :

master test2 = master(2,0);

Si valeurB vaut zéro test2.sousClassB n'est pas instancié, donc vaut zéro, et test2.sousClassB->GetValeur() plante.

Il y a un problème dans ta manière d'implémenter la chose.
Si tu instancies test et test2 en global, tu ne pourras pas afficher quoi que ce soit dans les constructeurs, car l'instanciation est faite avant l'exécution de setup().

#include "masterslave.h"

void setup() {
  Serial.begin(115200);

  Serial.printf("setup\n");
  master test = master(2,2);
  master test2 = master(2,0);

  Serial.print("groupeA = ");Serial.print(test.sousClassA->GetValeur());
  Serial.print("\t groupeB = ");Serial.println(test.sousClassB->GetValeur());
  
  test.AddDeux();
  test2.AddDeux();
  test.sousClassB->AddUn();
  if (test.sousClassA) {
    Serial.print("groupeA + 2 = ");Serial.print(test.sousClassA->GetValeur());
  }
  if (test.sousClassB) {
    Serial.print("\t groupeB + 3 = ");Serial.println(test.sousClassB->GetValeur());
  }
  Serial.println("=== TEST 2 après Add deux =====");
  if (test2.sousClassA) {
    Serial.print("groupeA = ");Serial.print(test2.sousClassA->GetValeur());
  }
  if (test2.sousClassB) {
    Serial.print("\t groupeB = ");
    Serial.println(test2.sousClassB->GetValeur());  // l'objet test2.sousClassB n'est pas déclarée
  }
}

void loop() {}

Comme je te l'avais dit, les contraintes sont importantes.
Mais tu peux aussi ajouter des méthodes à master :

    int getValeurA(void) {return sousClassA != 0 ? sousClassA->GetValeur() : 0;}
    int getValeurB(void) {return sousClassB != 0 ? sousClassB->GetValeur() : 0;}

Ensuite :

Serial.print(test.getValeurA());
// au lieu de : 
Serial.print(test.sousClassA->GetValeur());

C'était le but que ça plante, mais j’aurais pensé que le microcontrôleur reset...

Oui mais ... Non,

Si je veux aussi l'employer dans le loop() !

Il faut que je passe par la case .begin() comme si dessous ?

(sachant que les variables envoyé au constructeur sont des valeurs constantes)

inclus dans mon_exemple_v2 ici


#include "masterSlave.h"

#define TEST_1A 1

#define TEST_1B -9

#define TEST_2A 2

#define TEST_2B 2

master test;

master test2;

void setup() {

Serial.begin(115400);

test.begin(TEST_1A,TEST_1B);

test2.begin(TEST_2A,TEST_2B);

//...

}

Pour autant que les choses soient faites correctement et dans le bonne ordre, je trouves ça supportable même à mon faible niveau :slight_smile:

Tout à fait. Je voulais juste pas surcharger l'exemple et aussi voir comment l’accès à la sous_class réagissais.

Cela me parait lourd...

je me demande si vous n'avez pas plutôt besoin de la notion de fonction virtuelle et d'héritage...

un exemple :

class Parent {
  protected:
    int valeur;

  public:
    Parent(int val) : valeur(val) {}

    void ajouterUn() {
      valeur++;
    }

    int obtenirValeur() {
      return valeur;
    }

    virtual void direBonjour() {
      Serial.print("Bonjour de Parent -> "); Serial.println(valeur);
    }
};

class Enfant1 : public Parent {
  public:
    Enfant1(int val) : Parent(val) {}

    void direBonjour() override {
      Serial.print("Bonjour de Enfant1 -> "); Serial.println(valeur);
    }
};

class Enfant2 : public Parent {
  public:
    Enfant2(int val) : Parent(val) {}

    void direBonjour() override {
      Serial.print("Bonjour de Enfant2 -> "); Serial.println(valeur);
    }
};

Enfant1 e1(10);
Enfant2 e2(15);

Parent* liste[] = {&e1, &e2};

void setup() {
  Serial.begin(115200);
  for (auto& p : liste) p->direBonjour();
  for (auto& p : liste) p->ajouterUn();
  for (auto& p : liste) p->direBonjour();
}

void loop() {}

vous voyez que la fonction ajouterUn() n'est définie qu'une fois au niveau de la classe Parent et les 3 classes ont leur fonction direBonjour() qui leur est propre.

Comme les Enfants sont des spécialisations de la classe Parent (ce sont des Parents un peu spéciaux), on peut créer un tableau de pointeurs vers des Parents tout en y logeant des instances des Enfants.

Lorsque j'appelle ajouterUn() c'est la fonction dans la classe Parent qui est appelée, mais quand j'appelle la fonction virtuelle direBonjour() alors le compilateur est assez malin pour se rendre compte de la classe réelle qui est dans le tableau et donc d'appeler la bonne fonction.

C'est aussi mon impression.

@J-M-L WAOUH !! Pour moi, c'est un peu comme si je vous parlais en patois de chez moi
Thy dju, ben j'a rin pijo, tche vo dire chy code. Tchee don ! :wink:

Plus sérieusement, j'ai cherché à comprendre de quoi vous parlez et je suis tombé sur ce document que je suis en train de digérer. À propos de l'héritage, il dit :
"L’héritage permet de réutiliser des classes existantes en les enrichissant de fonctions et champs supplémentaires pour un usage plus précis."
C'est vrai que cela ressemble à ce que je voudrais faire.

Je vais vous réexpliquer mon projet plus en détail :

  • Sur le PC, j'ai AgOpenGPS (programme d'autoguidage de tracteur agricole en Open Source) qui communique avec des MCU (1 à 3 MCU selon le montage).
  • Les MCU transmettent à AgOpenGPS les valeurs des capteurs et pilotent les différents actionneurs du tracteur selon les données reçues d'AgOpenGPS.
  • J'ai modifié le programme d'AgOpenGPS pour qu'il envoie l'erreur de position du tracteur par rapport à la ligne de guidage (distance de la ligne en mm).
  • Le but est de pouvoir utiliser AgOpenGPS sans le dispositif qui actionne la direction, mais de le remplacer par une barre lumineuse dont les pixels représentent une erreur de X mm à gauche ou à droite de la ligne.
  • Le programme a aussi une autre barre lumineuse sur son écran symbolisant l'état de chaque section de l'outil accroché au tracteur. (Une section correspond, par exemple, à un jet sur une pompe à traiter.)
    AgOpenGPS peut actuellement gérer jusqu'à 64 sections. Ces sections ont comme état : Désactivé; Off manuel; Off automatique; Tourne à On; On manuel; On automatique; Tourne à Off.
    J'ai ajouté à AgOpenGPS l'envoi de l'état de ces sections pour pouvoir également les afficher via un des MCU sur un ruban de néoPixels.

vidéo de présantation d'AOG Par son créateur (en anglais) ou en français

Je me retrouve avec deux fonctions supplémentaires à rajouter à un MCU qui a déjà son programme existant.

Edit, le 17.06:
Ce que je veux dire, c'est que j'aimerais pouvoir ajouter facilement mon code au programme d'un des nombreux microcontrôleurs déjà existants, comme si j'ajoutais une bibliothèque avec juste quelques lignes pour faire fonctionner cette bibliothèque, tout en conservant les fonctionnalités du dit microcontrôleur.

J'aimerais, dans le code du MCU, pouvoir facilement choisir quelle(s) fonction(s) je veux utiliser et définir si j'utilise un pin par fonction ou les deux fonctions sur le même pin (un pin = une bande de néoPixels).
Pourquoi regrouper une partie de ces deux fonctions dans une fonction "maître" : (c'est surtout quand les deux fonctions sont sur le même ruban que les problèmes suivants apparaissent)

  • Si chaque fonction envoie des données au ruban de néoPixels sans un minimum de temps entre les envois, les données sont fusionnées et il y a un décalage de pixels.
  • Beaucoup de fonctions deviendraient redondantes.
  • La librairie Adafruit_Neopixels que j'utilise a des fonctions qui agissent sur tout le ruban. Il serait compliqué de les faire appliquer à des groupes de pixels différents.

En ce qui concerne les fonctions héritées, de ce que j'ai compris, je devrais programmer dans cette idée :

  • Les classes light_bar et section_bar qui gèrent chacune ce qui concerne leur fonctionnalité. (Par exemple : quels pixels sont allumés de quelle couleur, ...)
  • La classe bande_Neopixels gère tout ce qui concerne son bandeau (par exemple : la luminosité des LEDs, pixels.show(), ...). Ses instances correspondent au pin auquel elles sont rattachées.
  • La classe bande_Neopixels hérite des classes light_bar et section_bar si elles sont présentes. (Ou l'inverse ... à réfléchir !)

En faisant ainsi, dans la loop() du [.ion] :

  • Quand je reçois une valeur à transmettre à light_bar :
    • Si light_bar existe -> je lui transmets la valeur.
  • Même chose pour section_bar.
  • Quand je reçois une valeur à transmettre à bande_Neopixels_A ou à bande_Neopixels_B :
    • Si elle existe -> je lui transmets la valeur.
  • À chaque boucle ou à intervalle régulier :
    • Si bande_Neopixels_A existe -> afficher les pixels. "pixels.show()"
    • Si bande_Neopixels_B existe -> afficher les pixels. "pixels.show()"

sous quel forme se fait cet envoi ?

cette barre lumineuse ce sont les Neopixels, c'est ça ?

PS/

:slight_smile:

Dans Visual Studio, je format un message (pgn F7) pour les 24 première sections, puis si il y en a plus d'activées un deuxième message (pgn F6)

        // Section leds_bar 1 to 24
        public class CPGN_F7
        {
            /// <summary>
            /// PGN - 247 - F7
            /// Section sur 3bits = 8 sections sur 3 Bytes
            /// ----------------------------------------
            /// DEC | Bin   | color | état              |
            /// 0   |   000 | noir  |   désactivé       |
            /// 1   |   001 | vert  |   On-automatique  |
            /// 2   |   010 | jaune |   On-manuel       |
            /// 3   |   011 |       |   nc.             |
            /// 4   |   100 | bleu  |   Tourne à off    |
            /// 5   |   101 | violet|   Tourne à on     |
            /// 6   |   110 | rouge |   Off-automatique |
            /// 7   |   111 | rouge |   Off-manuel      |
            /// ----------------------------------------
            /// </summary>
            public byte[] pgn = new byte[] { 0x80, 0x81, 0x7f, 0xF7, 4, 255, 0, 0, 0, 0xCC };
            public int length = 4;
            public int nbr_section_isDay = 5;   // nbr de sections (> 64 = 64) + 65 si l'éclairage est sur jour. (Pour plus de 64 section renseigner CPGN_F6)
            public int sect1to24A = 6;
            public int sect1to24B = 7;
            public int sect1to24C= 8;
            public int crc = 9;

            public CPGN_F7()        //  F7 = 247 >>  Section_bar NeoPixels
            {
            }

            public void Reset()
            {
            }
        }


        // Section leds-bar 25 to 64
        public class CPGN_F6
        {
            /// <summary>
            /// PGN - 246 - F6    >>  Section_bar NeoPixels 25 to 64
            /// -->> Voir CPGN_F7
            /// </summary>
            public byte[] pgn = new byte[] { 0x80, 0x81, 0x7f, 0xF6, 6, 0, 0, 0, 0, 0, 0, 0xCC };
            public int length = 4;
            public int nbr_sections = 5;    // de 0 à 255
            public int sect25to48A = 6;
            public int sect25to48B = 7;
            public int sect25to48C = 8;
            public int sect49to72A = 9;
            public int sect49to72B = 10;
            //public int sect49to72C = 11;
            public int crc = 11;

            public CPGN_F6()            {
            }

            public void Reset()
            {
             }
        }

Et pour la light-bar:

        //Lightbar external
        public class CPGN_F9
            {
                /// <summary>
                /// 
                /// PGN - 249 - F9  * Copied by AgOpenGPS_v5-5_with_lightbar
                /// corss_track_error = 5 >>6
                /// ex_light_status : 1 -> on_manuel; 2 -> 0n_automatique; 3 -> off_automatique; 4 -> off_manuel; 9 -> non_connu 
                /// </summary>
                public byte[] pgn = new byte[] { 0x80, 0x81, 0x7f, 0xF9, 4, 0, 0, 0, 0, 0xCC };
                public int cross_track_error_msb = 5;
                public int cross_track_error_lsb = 6;
                public int is_day = 7;
                // public int libre = 8;
                public int crc = 9;

                public CPGN_F9()        //  F9 = 249 >>  Light Bar externe
                {
                }

                public void Reset()
                {
                }
            }

composition d'un message depuis ou vers AOG:

 byte[] { 0x80, 0x81, 0x7f, 0xF6, 6, 0, 0, 0, 0, 0, 0, 0xCC };

Les Bytes 0 à 2 corespondes à l'ID d'AOG,
Le Byte 3 corespondes à l'adresse (fonction) du message
Le Byte 4 le nombre de Bytes DATA
les Bytes suivants aux DATA à transmettre
Et le dernier Byte au CRC (code de contrôle du message.

Oui c'est la partie light_bar qui a un nombre de pixels defini dans le [.ino].
La partie sectios_bar, c'est aussi des neoPixels avec un nombre maxi de pixels aussi defini dans le [.ino].
Une video d'une light-bar avec une ancienne version d'AOG

Et c’est transmis comment à votre arduino ? Un message en binaire sur le port série ?

PS: j’ai édité votre message précédent pour mettre directement le lien YouTube sur une seule ligne, ça permet d’intégrer un lecteur dans votre post sans aller sur YouTube et voir des pubs.

Oui, si l'Arduino est connecté en USB.
AOG donne aussi la possibilité de connecter les MCU en Ethernet (UDP) et certains utilisateurs passent par le Wifi ou le Bluetooth.
Pour le moment, je reste en USB.
Pour les autres possibilités de connexion, je sais juste qu'elles existent...

Dans l'Arduino, la lecture du port série se déroule comme ceci :

  // Serial Receive
    //Do we have a match with 0x8081?
    if (Serial.available() > 4 && !isHeaderFound && !isPGNFound) {
      uint8_t temp = Serial.read();
      if (tempHeader == 0x80 && temp == 0x81) {
        isHeaderFound = true;
        tempHeader = 0;
      } else {
        tempHeader = temp;  //save for next time
        return;
      }
    }

    //Find Source, PGN, and Length
    if (Serial.available() > 2 && isHeaderFound && !isPGNFound) {
      Serial.read();  //The 7F or less
      pgn = Serial.read();
      dataLength = Serial.read();
      isPGNFound = true;
    }

    //The data package
    if (Serial.available() > dataLength && isHeaderFound && isPGNFound) {         
      // if (pgn == 239) {  // EF Machine Data
        // //reset watchdog
        // watchdogTimer = 0;
        // //Reset serial Watchdog
        // serialResetTimer = 0;
        // }
      // else if (pgn == 238)  //EE Machine Settings
      // else if (pgn == 236)  //EC Relay Pin Settings
      // else if (pgn == 254) {  // FE Machine
      // else if (pgn == 247) {}  // EF Machine Data
      #if NBR_LEDS_LIGHTBAR > 0
      if (pgn == 248) { } // F8 Light bar configue
      else if (pgn == 249) {  // F9 Light bar data
        lightBar.distance((int16_t)(Serial.read() << 8 | Serial.read()));

        #ifdef Auto_Day_Night
        { int8_t tempPhByte = Serial.read();
          if (tempPhByte == 2) lightBar.SetIsDay(false);
          else if (tempPhByte == 1) lightBar.SetIsDay(true);
          //SerialBT.print("IsDay = ");SerialBT.println(lightBar.GetIsDay(true));
        }
        #else
        Serial.read();
        #endif
        
        Serial.read();    //  read: crc
    } //END : (pgn == 249) F9 Light bar
    #endif

    //reset for next pgn sentence
    isHeaderFound = isPGNFound = false;
    pgn = dataLength = 0;
  }   // end Serial Receive

C'est la variante que j'utilisais quand j'avais uniquement la "light_bar". (tout mon code "dans un état brouillon" est disponible dans le #post5.
Naturellement, les adresses PGN (fonction) masquées ont des fonctions déjà définies dans le programme de base. Je les ai supprimées juste pour ne pas m'emmêler dans ma version de développement !

:+1: Merci, je ne savais pas comment le faire, maintenant je sais !

Si je regarde les résultats du bout de code ci-dessous, je m’aperçois que lors de l’héritage, la méthode héritante crée ses propres attributs de la classe héritée.

#ifndef TEST_H
#define TEST_H

class point { 
	public : 
		point(int x, int y){
      this->abs =x;
      this->ord =y;
    };
		int abs;
    int ord;
		void afficher () { Serial.print("p.abs = "); Serial.print(abs);Serial.print("\tp.ord = "); Serial.print(ord);} 
};
class couleur {
	public :
		String coul ;
		couleur ( String c ) : coul ( c ) {}
		void afficher () { Serial.print("color = "); Serial.print(coul);} 
};
class pixel : public point , public couleur { 
	public : 
		bool visible ;
		pixel ( point p , couleur c , bool b ) : point ( p ) , couleur ( c ) , visible ( b ) {}
		void afficher () { Serial.print("pixel.abs = "); Serial.print(abs);Serial.print("\tpixel.ord = "); Serial.print(ord);}
};

// Question : Est ce que plusieurs class peuvent hériter de la même class ? Comme si-dessous.
//     Raiponce: OUI.

class blink : public point , public couleur { 
	public : 
		bool _blink ;
		blink ( point p , couleur c , bool cl ) : point ( p ) , couleur ( c ) , _blink ( cl ) {}
		void afficher () { Serial.print("blink.abs = "); Serial.print(abs);Serial.print("\tblink.ord = "); Serial.print(ord);}
};

#endif

// dans .ino:
#include "test.h"

	point p (2 ,3);
	couleur c(" vert ");
	pixel pix (p ,c , true );
	blink bli (p ,c , true );

void setup() {
  Serial.begin(115200);

  Serial.println(">> Après déclarations:");
  //Serial.print("p.abs = ");Serial.print(p.abs);Serial.print("\t\tp.ord = ");Serial.println(p.ord);
	//Serial.print("pix.abs = ");Serial.print(pix.abs);Serial.print("\tpix.ord = ");Serial.println(pix.ord);
	//Serial.print("bli.abs = ");Serial.print(bli.abs);Serial.print("\tbli.ord = ");Serial.println(bli.ord);
	p.afficher(); Serial.println();
  pix.afficher(); Serial.println();
	bli.afficher(); Serial.println();

  Serial.println("\n  Modification des valeurs:");
  bli.abs = 8; Serial.print("bli.abs = 8");
	pix.point::ord = 6; Serial.println("\tpix.point::ord = 6");

  Serial.println(">> Après modification des valeurs:");
  //Serial.print("p.abs = ");Serial.print(p.abs);Serial.print("\t\tp.ord = ");Serial.println(p.ord);
	//Serial.print("pix.abs = ");Serial.print(pix.abs);Serial.print("\tpix.ord = ");Serial.println(pix.ord);
  //Serial.print("bli.abs = ");Serial.print(bli.abs);Serial.print("\tbli.ord = ");Serial.println(bli.ord);
  p.afficher(); Serial.println();
  pix.afficher(); Serial.println();
	bli.afficher(); Serial.println();
}

void loop() {}

Résultat dans le moniteur série:

>> Après déclarations:
p.abs = 2	p.ord = 3
pixel.abs = 2	pixel.ord = 3
blink.abs = 2	blink.ord = 3

  Modification des valeurs:
bli.abs = 8	pix.point::ord = 6
>> Après modification des valeurs:
p.abs = 2	p.ord = 3
pixel.abs = 2	pixel.ord = 6
blink.abs = 8	blink.ord = 3

Ce qui revient à dire que si deux enfants héritent du même père, lorsque le père vieillit d’une année, je dois aussi dire à chaque enfant que leur père vieillit d’une année !

Oui le père n'est pas partagé - c'est pas comme cela qu'il faut comprendre la programmation orientée objet

Voyez plutôt cela comme un héritage génétique :slight_smile: ➜ les enfants ont les gènes (attributs) des parents.


OK pour les code de lecture du port série. Vous prenez des risque en laissant le buffer série se remplir pour pouvoir extraire une trame plus ou moins d'un seul tenant

car la buffer ne fait que 64 octets. Si vous avez de nombreuses communications successives, le buffer pourrait déborder. Généralement on préfère lire les données au fil de l'eau et quand on a tout reçu, on traite la trame.