POO - création librairie - création d'une classe

Bonjour,
Je me lance dans l'apprentissage du C++. J'ai acheté 3 livres, les deux premiers sont très simples et le troisième est du niveau universitaire ou d'école d'ingénieur (je ne sais pas encore si je pourrai aller jusqu'au bout !). J'ai attaqué le premier mais les trois reprennent le C (c'est bien normal), ce qui me rend impatient. Du coup parallèlement à mes lectures j'essaye par mes propres moyens de créer une librairie. Je vous présente ce que j'ai fait :
A partir de deux int, une classe nommée Calcul possède deux méthodes une qui multiplie les deux chiffres et l'autre qui les soustrait :
1/ fichier d'en tête

#ifndef Calcul_h
#define Calcul_h

#include <Arduino.h>

class Calcul{
public:
Calcul(int A,int B);
int calculMult(void);
int calculSous(void);
private:
int _A;
int _B;
int C;
};
#endif

2/ Le fichier source

#include "Calcul.h"

Calcul::Calcul(int A,int B) {
_A = A;
_B = B;
}

int Calcul::calculMult(){
C = _A * _B;
return C;
}
int Calcul::calculSous() {
C = _A - _B;
return C;
}

3/ Le fichier ino

#include <Calcul.h>

Calcul calc(45, 15);
Calcul calc2(125, 126);

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

}

void loop() {
  Serial.print("Instance calc : ");  Serial.print("\t");Serial.print(calc.calculMult()); Serial.print("\t");  Serial.println(calc.calculSous());
  Serial.print("Instance calc2 : ");  Serial.print("\t");Serial.print(calc2.calculMult()); Serial.print("\t");  Serial.println(calc2.calculSous());
}

Sur arduino uno j'ai 4 warning :

D:\Utilisateur\Documents\ArduinoData\packages\arduino\hardware\avr\1.8.5\cores\arduino\new.cpp: In function 'void* operator new(std::size_t, std::nothrow_t)':
D:\Utilisateur\Documents\ArduinoData\packages\arduino\hardware\avr\1.8.5\cores\arduino\new.cpp:59:60: warning: unused parameter 'tag' [-Wunused-parameter]
 void * operator new(std::size_t size, const std::nothrow_t tag) noexcept {
                                                            ^~~
D:\Utilisateur\Documents\ArduinoData\packages\arduino\hardware\avr\1.8.5\cores\arduino\new.cpp: In function 'void* operator new [](std::size_t, const std::nothrow_t&)':
D:\Utilisateur\Documents\ArduinoData\packages\arduino\hardware\avr\1.8.5\cores\arduino\new.cpp:68:63: warning: unused parameter 'tag' [-Wunused-parameter]
 void * operator new[](std::size_t size, const std::nothrow_t& tag) noexcept {
                                                               ^~~
D:\Utilisateur\Documents\ArduinoData\packages\arduino\hardware\avr\1.8.5\cores\arduino\new.cpp: In function 'void operator delete(void*, const std::nothrow_t&)':
D:\Utilisateur\Documents\ArduinoData\packages\arduino\hardware\avr\1.8.5\cores\arduino\new.cpp:103:55: warning: unused parameter 'tag' [-Wunused-parameter]
 void operator delete(void* ptr, const std::nothrow_t& tag) noexcept {
                                                       ^~~
D:\Utilisateur\Documents\ArduinoData\packages\arduino\hardware\avr\1.8.5\cores\arduino\new.cpp: In function 'void operator delete [](void*, const std::nothrow_t&)':
D:\Utilisateur\Documents\ArduinoData\packages\arduino\hardware\avr\1.8.5\cores\arduino\new.cpp:106:57: warning: unused parameter 'tag' [-Wunused-parameter]
 void operator delete[](void* ptr, const std::nothrow_t& tag) noexcept {
                                                         ^~~

Pourtant ça téléverse et ça fonctionne parfaitement ...

Instance calc : 	675	30
Instance calc2 : 	15750	-1

Il y a quelque chose que j'ai mal fait mais je n'arrive pas à trouver quoi.

Merci pour votre patience.

Aucun problème 0 warning.
Peut-être faire le ménage dans le répertoire temporaire où sont conservés les résultats de compilations précédentes.

Merci @fdufnews,
Je vais voir de ce côté.
Sur ESP32, ça ne téléverse pas du tout :

In file included from D:\Utilisateur\Documents\ArduinoData\packages\esp32\hardware\esp32\2.0.4\cores\esp32/WCharacter.h:23,
                 from D:\Utilisateur\Documents\ArduinoData\packages\esp32\hardware\esp32\2.0.4\cores\esp32/Arduino.h:164,
                 from sketch\Calcul_Biblio.ino.cpp:1:
D:\Utilisateur\Documents\Arduino\libraries\Calcul/Calcul.h:13:5: error: expected unqualified-id before numeric constant
 int _B;
     ^~
exit status 1
Erreur de compilation pour la carte DOIT ESP32 DEVKIT V1

Sur uno, je n'ai aucun warnings, cela semble ne pas venir du code.

le membre C de ta classe est inutile. Il consomme quelques octets pour rien.
Tu peux faire

int Calcul::calculMult(){
  int produit = _A * _B;
  return produit;
}

Par ailleurs, pour cette classe, tu ferais mieux de stocker non pas A et B, mais A*B et A-B, pour ne pas les recalculer à chaque appel.

@philippe86220, l'erreur indique que l'opérateur new est définit avec 3 paramètres, mais que l'implémentation n'utilise pas le paramètre tag.
Donc c'est normal que le programme fonctionne et comme le problème se situe dans le framework d'Arduino, le problème ne vient pas de ton programme.
Tu n'a pas les même warning si tu n'utilise pas ta classe?

Je suis surpris de ton erreur avec l'ESP32, j'ai l'impression que le fichier d'en-tête t'empêche d'utiliser le caractère _ en début de variable.
Tu peux juste essayer de ne pas nommer tes variables global avec ce caractère?

Merci @terwal, vous avez raison sur ESP32 bizarrement _ ne passe pas, du coup je n'ai plus d'erreur sur cette plateforme.

#ifndef Calcul_h
#define Calcul_h

#include <Arduino.h>

class Calcul{
public:
Calcul(int A,int B);
int calculMult();
int calculSous();
private:
int vA;
int vB;
};
#endif
#include "Calcul.h"

Calcul::Calcul(int A,int B) {

vA = A;
vB = B;
}

int Calcul::calculMult(){
int produit  = vA * vB;
return produit ;
}
int Calcul::calculSous() {
int soust = vA - vB;
return soust ;
}



Merci @biggil,J'ai pris en compte votre remarque.

Sur Uno j'ai remarqué qu'aprés lancement de l'IDE 1.8.19, les warning sont présents au premier téléversement mais pas si je téléverse de nouveau. Bizarre...

Si on sélectionne un ESP32 _B est une macro définie dans ctype.h
#define _B 0200

Merci @kamill du coup ceci explique cela ...

Il est où ce répertoire @fdufnews ? Peut-être AppData/Local/Temp ?
Merci.

Oui c'est bien ce répertoire mais le netoyage ne change rien. Les messages sont présents pour tous les progs où j'utilise des bibliothèques et uniquement au premier téléversement sur UNO.

Oui, parce que les fichiers compilés sont conservés dans un répertoire temporaire. Si le fichier compilé n'est pas modifié il n'est pas recompilé et donc les warning ne remontent pas

Merci @fdufnews.
J'ai tout réinstaller et ça refonctionne correctement. Oupssssssss
J'aurai peut-être pu faire plus simple mais je n'ai pas trouvé.

Merci.

pour parfaire la déclaration de ta classe, il faudrait ajouter l'attribut const aux 2 méthodes.

int calculMult() const;
int calculSous() const;

En effet ces deux méthodes ne modifient pas les membres de la classe.
On pourrait croire que c'est -juste de la décoration, mais non.
C'est une excellente habitude de programmation que de déclarer const les méthodes qui le sont.
Ca servira un jour, je te garantis.

Merci @biggil,
Du coup ==>

#ifndef Calcul_h
#define Calcul_h

#include <Arduino.h>

class Calcul{
public:
Calcul(int A,int B);
int calculMult() const;
int calculSous() const;
private:
int vA;
int vB;
//int C;
};
#endif
#include "Calcul.h"

Calcul::Calcul(int A,int B) {

vA = A;
vB = B;
}

int Calcul::calculMult() const {
int produit  = vA * vB;
return produit ;
}
int Calcul::calculSous() const {
int soust = vA - vB;
return soust ;
}

Je retiens que mes deux méthodes ne modifient pas l’objet pour lequel elle sont appelées, du coup elle peuvent être déclarées comme constantes. Au même titre q'une donnée constante classique, cela permet au code généré de disposer de la valeur immédiate plutôt que d'aller la chercher dans la case ou a été stockée la valeur d'une variable. Ici, il s'agit de disposer du résultat d'un calcul ?

encore 2 choses et ta classe commencera à avoir de la gueule.
1-
Tu n'as pas déclaré de destructeur. Ici tu n'en as pas besoin bien sûr, mais c'est une bonne habitude d'en déclarer un, même vide. Ainsi, le jour où ta classe se complexifie et a besoin d'un destructeur, le code est déjà là (même vide) tu auras moins tendance à l'oublier. Donc:
~Calcul () {}

2 - Il faut indenter ton code correctement pour le rendre plus lisible. Dans l'IDE Arduino, rien de plus facile : tu tapes Control-T (ou pomme-T sur Mac)

??? pas compris la question.
const est un engagement moral que prend que une fonction membre à ne pas modifier l'objet auquel elle s'applique. C'est tout, n'y cherche rien d'autre.
C'est une sécurité pour le programmeur qui utilise la fonction : il est sûr que l'objet ne sera pas modifié.

Merci @biggil,
Voilà :

#ifndef Calcul_h
#define Calcul_h

#include <Arduino.h>

class Calcul {
  public:

    // Constructeur
    Calcul(int A, int B);
    int calculMult() const;
    int calculSous() const;

    // Destructeur
    ~Calcul();

  private:
    int vA;
    int vB;
    //int C;
};
#endif
#include "Calcul.h"

// Initialisation
Calcul::Calcul(int A, int B) {

  vA = A;
  vB = B;
}

int Calcul::calculMult() const {
  int produit  = vA * vB;
  return produit ;
}
int Calcul::calculSous() const {
  int soust = vA - vB;
  return soust ;
}

// Destruction
Calcul::~Calcul() {}




Je n'avais pas identé mon code car je travaillais avec des fichiers TXT.

Merci beaucoup
Bon dimanche.

il n'y a aucun besoin d'inclure Arduino.h dans le .h de ta classe.

Enfin, pour initialiser les membres dans le constructeur, on écrit plutôt :

Calcul::Calcul(int A, int B) 
: vA ( A ),
  vB ( B )
{}

Ici ça ne change rien, mais parfois il n'est pas possible d'initialiser un membre par une affectation explicite (en fait, après la construction des classes de base, il n'y en a pas ici)

J'avais appris dans ma jeunesse qu'il y avait des conventions d'écriture en C, à savoir que les variables et les noms de fonctions s'écrivaient avec des minuscules (une majuscule en début de mot pour séparer), les constantes en majuscules et les noms des classes avec une majuscule suivie de minuscules. Cela donnerait:
Calcul::Calcul(int a, int b)
Plus compliqué pour vA car on peut l'entendre comme valeur de a.
et la création serait: Calcul Calc(45, 15);

Doit on préférer ces conventions? Je remarque bien souvent des déclarations de pins style
const int pinMoteur = 2;
alors que j'aurais tendance à écrire:
const byte PIN_MOTEUR = 2;



Je me pose aussi la question de la préférence entre:
int Calcul::calculMult() const {
  int produit  = vA * vB;
  return produit ;
}

et

int Calcul::calculMult() const {
  return vA * vB;
}

La variable supplémentaire semble ne pas être créée, la taille du code et des données est la même. J'ai tendance à supprimer les variables inutiles. Le code plus compact est-il plus facile à lire? J'ai l'impressions que moins on a de variables à mémoriser mieux cela vaut. Il est vrai que j'ai commencé la programmation du temps ou le compilateur n'optimisait quasiment pas, et que l'optimisation était faite par le programmateur lui-même (une division par 2^n n'était pas transformée en décalage par exemple)