Je dispose des trois fichiers suivants qui forme un code qui compare des durées (heures, minutes, secondes) :
Duree.cpp :
#include "Duree.h"
#include <iostream>
Duree::Duree(int heures, int minutes, int secondes) : m_heures(heures), m_minutes(minutes), m_secondes(secondes)
{
}
////version courte de la méthode juste en dessous
//bool Duree::estEgal(Duree const& b) const
//{
// return (m_heures == b.m_heures && m_minutes == b.m_minutes && m_secondes == b.m_secondes); //Teste si a.m_heure == b.m_heure etc.
//}
//version longue de la méthode juste au dessus. Elle entre dans la méthode juste en
//dessous
bool Duree::estEgal(Duree const& b) const
{
//Teste si a.m_heure == b.m_heure etc.
if (m_heures == b.m_heures && m_minutes == b.m_minutes && m_secondes == b.m_secondes)
return true;
else
return false;
}
bool operator==(Duree const& a, Duree const& b)//pour pouvoir utiliser le "=="
{
return a.estEgal(b);
}
//apparemment déjà défini en même temps que pour ==
bool operator!=(Duree const& a, Duree const& b)
{
// if(a==b)
// {
// return false;
// }
// else
// {
// return true;
// }
//version plus courte que le if else juste au-dessus
return not (a==b);//retourner le contraire de a==b
}
//pour pouvoir utiliser le <
bool operator<(Duree const& a, Duree const& b)
{
return a.estPlusPetitQue(b);
}
//pour pouvoir utiliser le <. La méthode entre dans celle juste au-dessus
bool Duree::estPlusPetitQue(Duree const& b)const//pour pouvoir utiliser le <
{
if(m_heures < b.m_heures)
return true;
else if(m_heures == b.m_heures and m_minutes < b.m_minutes)
return true;
else if(m_heures == b.m_heures and m_minutes == b.m_minutes and m_secondes < b.m_secondes)
return true;
else
return false;
}
bool operator>(Duree const &a, Duree const& b)
{
return a.estPlusGrandQue(b);
}
bool Duree::estPlusGrandQue(Duree const& b)const//pour pouvoir utiliser le <
{
if(m_heures > b.m_heures)
return true;
else if(m_heures == b.m_heures and m_minutes > b.m_minutes)
return true;
else if(m_heures == b.m_heures and m_minutes == b.m_minutes and m_secondes > b.m_secondes)
return true;
else
return false;
}
bool operator<=(Duree const &a, Duree const& b)
{
return a.estPlusPetitOuEgalQue(b);
}
bool Duree::estPlusPetitOuEgalQue(Duree const& b)const//pour pouvoir utiliser le <
{
if(m_heures == b.m_heures and m_minutes == b.m_minutes and m_secondes <= b.m_secondes)
return true;
else if(m_heures == b.m_heures and m_minutes <= b.m_minutes)
return true;
else if(m_heures <= b.m_heures)
return true;
else
return false;
}
//bool operator==(Duree const& a, Duree const& b)//pour pouvoir utiliser le "=="
//{
// //Teste si a.m_heure == b.m_heure etc.
// if (a.m_heures == b.m_heures && a.m_minutes == b.m_minutes && a.m_secondes == b.m_secondes)
// return true;
// else
// return false;
//}
//int Duree::conversionEnMinutes(int m_secondes)
//{
// if (m_secondes > 60)
// {
// m_minutes += m_secondes/60;
// m_secondes %= 60;
// }
//}
//
//int Duree::conversionEnHeures(int m_minutes)
//{
// if (m_minutes > 60)
// {
// m_heures += m_minutes/60;
// m_minutes %= 60;
// }
//}
//void Duree::afficherDuree()
//{
// cout << m_heures << " " << m_secondes << " " << m_secondes << endl;
//}
main.cpp :
#include <iostream>
#include "Duree.h"
using namespace std;
int main()
{
Duree duree1(0, 20, 28), duree2(0, 10, 28);
//utilisation du ==
if (duree1 == duree2)
cout << "Les durees sont identiques" << endl;
else
cout << "Les durees sont differentes" << endl;
//utilisation du !=
if (duree1 != duree2)
cout << "Les durees sont differentes" << endl;
else
cout << "Les durees sont identiques" << endl;
//utilisation du <
if (duree1 < duree2)
cout << "La premiere duree est plus petite" << endl;
else
cout << "La premiere duree n'est pas plus petite" << endl;
//utilisation du >
if (duree1 > duree2)
cout << "La premiere duree est plus grande" << endl;
else
cout << "La première duree n'est pas plus grande" << endl;
//utilisation du <=
if (duree1 <= duree2)
cout << "La premiere duree est plus petite ou egale" << endl;
else
cout << "La premiere duree n'est pas plus petite ou egale" << endl;
return 0;
}
Duree.h :
#ifndef DUREE_H_INCLUDED
#define DUREE_H_INCLUDED
class Duree
{
public:
Duree(int heures = 0, int minutes = 0, int secondes = 0);
bool estEgal(Duree const& b) const;//pour utiliser le ==
bool estPlusPetitQue(Duree const& b)const;//pour utiliser le <
bool estPlusGrandQue(Duree const& b)const;//pour utiliser le >
bool estPlusPetitOuEgalQue(Duree const& b)const;//pour utiliser le <=
//méthode de conversion si les minutes ou secondes sont données supérieures à 60
// int conversionEnMinutes(int m_secondes);
// int conversionEnHeures(int m_minutes);
// void afficherDuree();
private:
int m_heures;
int m_minutes;
int m_secondes;
};
bool operator==(Duree const& a, Duree const& b);//pour pouvoir utiliser le "=="
bool operator!=(Duree const& a, Duree const& b);//pour pouvoir utiliser le "!="
bool operator<(Duree const& a, Duree const& b);//pour pouvoir utiliser le "<"
bool operator>(Duree const &a, Duree const& b);//pour pouvoir utiliser le ">"
bool operator<=(Duree const &a, Duree const& b);//pour pouvoir utiliser le "<="
#endif // DUREE_H_INCLUDED
J'essaie de faire en sorte de pouvoir utiliser l'opérateur <= en POO. Le problème est que le programme m'affiche que la première durée est plus petite ou égale alors qu'il devrait afficher que la première durée n'est pas plus petite ou égale quand les durées sont :
Duree duree1(0, 20, 28), duree2(0, 10, 28);
mais qu'il m'affiche que la première durée n'est pas plus petite ou égale quand les durées sont :
Duree duree1(1, 20, 28), duree2(0, 10, 28);
J'ai cherché l'erreur à ce niveau du programme dans le fichier Duree.cpp, là où elle doit sûrement se trouver, en le modifiant plusieurs fois de sorte à avoir le bon affichage sans la trouver :
bool operator<=(Duree const &a, Duree const& b)
{
return a.estPlusPetitOuEgalQue(b);
}
bool Duree::estPlusPetitOuEgalQue(Duree const& b)const//pour pouvoir utiliser le <
{
if(m_heures == b.m_heures and m_minutes == b.m_minutes and m_secondes <= b.m_secondes)
return true;
else if(m_heures == b.m_heures and m_minutes <= b.m_minutes)
return true;
else if(m_heures <= b.m_heures)
return true;
else
return false;
}
Quelqu'un verrait-il ou l'erreur dans le programme, se trouve-t-elle ?
Ca serait aussi commode d'avoir un constructeur qui prend un nombre de secondes pour en faire une Duree, mais comme tu as eu l'idée "géniale" de donner des paramètres par défaut à ton constructeur, ça le fait pas directement.
@rouIoude J'ai fini par me rendre compte que les heures, minutes et secondes étaient mal bornées. J'ai donc modifié et testé la méthode "estPlusPetitOuEgalQue" comme ceci qui à l'air de marcher comme voulu :
bool Duree::estPlusPetitOuEgalQue(Duree const& b)const//pour pouvoir utiliser le <
{
if(m_heures <= b.m_heures and m_minutes <= b.m_minutes and m_secondes <= b.m_secondes)
return true;
// else if(m_heures == b.m_heures and m_minutes <= b.m_minutes)
// return true;
// else if(m_heures <= b.m_heures and m_minutes == b.m_minutes and m_secondes )
// return true;
else
return false;
}
J'en ai profité pour faire de même pour l'opérateur >= en ajoutant les compléments suivants aux fichiers :
fichier Duree.cpp :
bool operator>=(Duree const &a, Duree const& b)
{
return a.estPlusGrandOuEgalQue(b);
}
bool Duree::estPlusGrandOuEgalQue(Duree const& b)const//pour pouvoir utiliser le >=
{
if(m_heures >= b.m_heures and m_minutes >= b.m_minutes and m_secondes >= b.m_secondes)
return true;
else
return false;
}
fichier main.cpp :
//utilisation du >=
if (duree1 >= duree2)
cout << "La premiere duree est plus grande ou egale" << endl;
else
cout << "La premiere duree n'est pas plus grande ou egale" << endl;
Dans la classe Duree du fichier Duree.h :
bool estPlusGrandOuEgalQue(Duree const& b)const;//pour pouvoir utiliser le >=
et à l'extérieur de la classe Duree toujours dans le fichier Duree.h
bool estPlusGrandOuEgalQue(Duree const& b)const;//pour pouvoir utiliser le >=
Voici les fichiers finaux :
fichier Duree.cpp :
#include "Duree.h"
#include <iostream>
Duree::Duree(int heures, int minutes, int secondes) : m_heures(heures), m_minutes(minutes), m_secondes(secondes)
{
}
////version courte de la méthode juste en dessous
//bool Duree::estEgal(Duree const& b) const
//{
// return (m_heures == b.m_heures && m_minutes == b.m_minutes && m_secondes == b.m_secondes); //Teste si a.m_heure == b.m_heure etc.
//}
//version longue de la méthode juste au dessus. Elle entre dans la méthode juste en
//dessous
bool Duree::estEgal(Duree const& b) const
{
//Teste si a.m_heure == b.m_heure etc.
if (m_heures == b.m_heures && m_minutes == b.m_minutes && m_secondes == b.m_secondes)
return true;
else
return false;
}
bool operator==(Duree const& a, Duree const& b)//pour pouvoir utiliser le "=="
{
return a.estEgal(b);
}
//apparemment déjà défini en même temps que pour ==
bool operator!=(Duree const& a, Duree const& b)
{
// if(a==b)
// {
// return false;
// }
// else
// {
// return true;
// }
//version plus courte que le if else juste au-dessus
return not (a==b);//retourner le contraire de a==b
}
//pour pouvoir utiliser le <
bool operator<(Duree const& a, Duree const& b)
{
return a.estPlusPetitQue(b);
}
//pour pouvoir utiliser le <. La méthode entre dans celle juste au-dessus
bool Duree::estPlusPetitQue(Duree const& b)const//pour pouvoir utiliser le <
{
if(m_heures < b.m_heures)
return true;
else if(m_heures == b.m_heures and m_minutes < b.m_minutes)
return true;
else if(m_heures == b.m_heures and m_minutes == b.m_minutes and m_secondes < b.m_secondes)
return true;
else
return false;
}
bool operator>(Duree const &a, Duree const& b)
{
return a.estPlusGrandQue(b);
}
bool Duree::estPlusGrandQue(Duree const& b)const//pour pouvoir utiliser le <
{
if(m_heures > b.m_heures)
return true;
else if(m_heures == b.m_heures and m_minutes > b.m_minutes)
return true;
else if(m_heures == b.m_heures and m_minutes == b.m_minutes and m_secondes > b.m_secondes)
return true;
else
return false;
}
bool operator<=(Duree const &a, Duree const& b)
{
return a.estPlusPetitOuEgalQue(b);
}
bool Duree::estPlusPetitOuEgalQue(Duree const& b)const//pour pouvoir utiliser le <
{
if(m_heures <= b.m_heures and m_minutes <= b.m_minutes and m_secondes <= b.m_secondes)
return true;
// else if(m_heures == b.m_heures and m_minutes <= b.m_minutes)
// return true;
// else if(m_heures <= b.m_heures and m_minutes == b.m_minutes and m_secondes )
// return true;
else
return false;
}
bool operator>=(Duree const &a, Duree const& b)
{
return a.estPlusGrandOuEgalQue(b);
}
bool Duree::estPlusGrandOuEgalQue(Duree const& b)const//pour pouvoir utiliser le >=
{
if(m_heures >= b.m_heures and m_minutes >= b.m_minutes and m_secondes >= b.m_secondes)
return true;
else
return false;
}
// définition
Duree Duree::depuisSecondes(int secondes) {
int s = secondes % 60;
int m = (secondes / 60) % 60;
int h = secondes / 3600;
// retour durée construite
return {h, m, s};
}
fichier main.cpp :
#include <iostream>
#include "Duree.h"
using namespace std;
int main()
{
Duree duree1(1, 10, 28), duree2(0, 10, 28);
//utilisation du ==
if (duree1 == duree2)
cout << "Les durees sont identiques" << endl;
else
cout << "Les durees sont differentes" << endl;
//utilisation du !=
if (duree1 != duree2)
cout << "Les durees sont differentes" << endl;
else
cout << "Les durees sont identiques" << endl;
//utilisation du <
if (duree1 < duree2)
cout << "La premiere duree est plus petite" << endl;
else
cout << "La premiere duree n'est pas plus petite" << endl;
//utilisation du >
if (duree1 > duree2)
cout << "La premiere duree est plus grande" << endl;
else
cout << "La première duree n'est pas plus grande" << endl;
//utilisation du <=
if (duree1 <= duree2)
cout << "La premiere duree est plus petite ou egale" << endl;
else
cout << "La premiere duree n'est pas plus petite ou egale" << endl;
//utilisation du >=
if (duree1 >= duree2)
cout << "La premiere duree est plus grande ou egale" << endl;
else
cout << "La premiere duree n'est pas plus grande ou egale" << endl;
// usage
auto d = Duree::depuisSecondes((3*3600 + 15*60 + 32));
return 0;
}
fichier Duree.h :
#ifndef DUREE_H_INCLUDED
#define DUREE_H_INCLUDED
class Duree
{
public:
Duree(int heures = 0, int minutes = 0, int secondes = 0);
bool estEgal(Duree const& b) const;//pour utiliser le ==
bool estPlusPetitQue(Duree const& b)const;//pour utiliser le <
bool estPlusGrandQue(Duree const& b)const;//pour utiliser le >
bool estPlusPetitOuEgalQue(Duree const& b)const;//pour utiliser le <=
bool estPlusGrandOuEgalQue(Duree const& b)const;//pour pouvoir utiliser le >=
// déclaration
static Duree depuisSecondes(int secondes);
private:
int m_heures;
int m_minutes;
int m_secondes;
};
bool operator==(Duree const& a, Duree const& b);//pour pouvoir utiliser le "=="
bool operator!=(Duree const& a, Duree const& b);//pour pouvoir utiliser le "!="
bool operator<(Duree const& a, Duree const& b);//pour pouvoir utiliser le "<"
bool operator>(Duree const &a, Duree const& b);//pour pouvoir utiliser le ">"
bool operator<=(Duree const &a, Duree const& b);//pour pouvoir utiliser le "<="
bool operator>=(Duree const &a, Duree const& b);//pour pouvoir utiliser le ">="
#endif // DUREE_H_INCLUDED
@michelbillaud "auto" est une instruction à laquelle il faut donner un nom pour appeler une fonction static avec en paramètre les nombres de son choix, est-ce bien cela ?
Tu paies un mauvais design choisi dans l'exo. Dans la vraie vie, on a une seule valeur (qui sera un nombre de secondes). On ne s'amuse pas à comparer chaque paires de champs, avec < sur la première paire, sinon si == sur la première paire, on regarde < sur la 2e, et sinon, == sur la 2e et puis < sur la 3e, etc.
Non. C'est la mort -- même si le C++20 sait maintenant le faire automatiquement).
Bref => je vote pour la solution de Michel => calcul du nombre total de secondes, et on les compare. Ou mieux, en interne on ne stocke que ce nombre, ce qui va simplifier toutes les définitions. On ne calculera les version hh:mm:ss uniquement lors des dialogues avec un éventuel humain (affichage, développeur qui construit un objet Duree).
Sinon, pourquoi faire: "if (expression) return true; else return false;" au lieu de ... "return expression;"?
Et nul besoin de toutes ces fonctions estPlusGrand, EstPlusPetit, etc, etc. En Java je ne dis pas. En C++ on aura les opérateurs. En python on aura les __lt__, & cie.
Le mot-clé auto sert dans les définitions de variables avec initialisation, de la forme
auto nom_de_variable = expression;
Et déclare la variable avec le type du résultat de l'expression.
Ça a été introduit pour faciliter l'écriture des fonctions génériques en particulier, quand on ne sait pas trop ce que seront les types.
Mais ça a un impact intéressant :
Clairement on va l'utiliser quand le type de la variable est ce qui correspond de toute évidence à ce qu'on veut
auto p = new Elephant("dumbo");
Parce que c'est aussi facile à lire que Éléphant *p = etc.
on va réserver les déclarations explicites au cas comme
Animal *m = new Mouse("mickey");
Parce que là, la réduction de type ne donnerait pas ce qu'on veut (un pointeur d'un type plus général)
Du coup, NE PAS utiliser auto, c'est un signal pour attirer l'attention : on n'a pas mis auto parce qu'il y a une raison qui empêche de le faire. Il faut faire attention.
Et donc, pour ne pas perturber le lecteur avec de fausses alertes, il faut mettre auto partout où le type de la variable est évident.
Bref, on passe d'un truc "gadget" pour simplifier des écritures compliquees, à un truc qu'il faut utiliser autant que possible.
---
De mémoire, dans ma vie précédente quand on donnaît l'exercice sur les Durees (c'était pas moi le chef de ce cours, fallait faire avec les exos de celui qui préparait...) on finissait par
montrer que l'implémentation est bien plus simple avec un choix de représentation interne en nombre de secondes
Et que c'est possible de faire ce choix, parce que ce qui est imposé, c'est l'API (les fonctions publiques). Et que le code client est indépendant de l'implémentation.
Conclusion : bien séparer les deux. Un objet, c'est pas une agrégation de de variables privées avec des accesseurs pour chacune, comme le laissent croire des exemples et des exercices traditionnellement très mal choisis (objets "plain old data"). Un objet, ça fait des choses.
Si jamais on change le type de la collection que l'on parcours mais que l'on a toujours besoin de parcourir la colllection d'objets, il n'y aura pas besoin de faire de modification au niveau du for.
Cela dit je suis plutôt reticent à 'auto' en règle générale, car j'aime bien connaître le type que je manipule, surtout avec des fonctions de la bibliothèque standard ou des bibliothèques tierces. Donc je l' utilise avec parcimonie. Je crois que l'utilisateur de ce forum 'fvirtman' est de cet avis là également (vu dans un sujet précédent il me semble).
y a toujours des gens opposés au progrès :-) Je ne dis pas que c'est une règle générale, mais que ça va probablement avoir tendance à le devenir, assez naturellement, vu que ça évite des écritures et des lectures inutiles. Tout comme ajouter const pour les variables qui, euh, ne varient pas, en fait, mais sont juste là pour poser une valeur intermédiaire.
> car j'aime bien connaître le type que je manipule
Aussi. Mais de toutes façons il faut que je détermine le type de l'expression, même si le type st explicite, pour vérifier que c'est cohérent. Ce qui est garanti par auto, qui me permettra de me concentrer sur les qualificatifs const, la présence d'un & pour une référence, etc, informations qui seraient un peu noyées dans des écritures redondantes et lourdingues dont C++ a le secret.
> auto dans for range loop
C'est encore plus flagrant dans les boucles par itérateur, quand on en a besoin (il y a aussi des ennemis du progrès à ce sujet)
void foo(std::vector<int> &v) {
for (std::vector<int>::iterator it = v.begin(); it != v.end(); it++) {
// ...
}
// versus:
for (auto it = v.begin(); it != v.end(); it++) {
// ...
}
}
Ok, je saisis l' idée. Dans ce cas si la variable 'const auto delta' est utilisé à plus d'un endroit dans le code autant en faire une fonction qui va retourner la valeur en question pour ne pas contrevenir au DRY ou alors si les types sont primitifs et tous des constantes/connus au moment de la compilation le mieux serait d' utiliser 'constexpr' TYPE NOM = /* calcul ici */;
Si le calcul est fait dans une fonction, pourquoi pas, on l'utilisera ainsi
const auto delta = discriminant(a, b, c);
si en dessous on a besoin plusieurs fois du même delta. Pour tester si il est positif et alors calculer sa racine.
Mais en tout cas dans un contexte où a, b et c ont des valeurs fixées, on ne change pas la valeur de delta, et par securité/autodocumentation du code, on peut mettre const. Et donc peut être qu'on doit, en plus de pouvoir.
Ps. Pour l'optional, ça résout un dilemme de programmation qui se posait quand on avait besoin de récupérer des données qui peuvent être absentes (pop d'une pile, lecture d'une ligne de fichier etc)
Dans l'approche traditionnelle d'il y a un demi siècle, on utilisait 2 etapes. Avec deux variantes
Style pascal : on teste d'abord si ça existe, et ensuite on récupère la données
Style C : on lance la lecture, et ensuite un code de retour nous dit si ça a marché ou pas.
En fait derrière il y a l'influence historique FORTRAN, concevoir les choses en termes d'opérations primitives qui ne retournent pas d'objets "composites".
Ou alors avec des données Out-of-band, le pointeur NULL quand malloc échoue, un entier négatif pour getc quand il n'y a plus de caractères (char codé sous forme d'un entier positif !), bref, ca sent le bricolage.
- Edité par michelbillaud 22 juin 2023 à 9:09:24
Erreur au niveau d'un opérateur
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Mon site web de jeux SDL2 entre autres : https://www.ant01.fr
Mon site web de jeux SDL2 entre autres : https://www.ant01.fr
Mon site web de jeux SDL2 entre autres : https://www.ant01.fr