Partage

Operator

1 juin 2015 à 15:57:56

Salut encore en faite j'ai fait une petit remarque sur l'operator+= 

c'est que si on appelle l'operator += pour faire un calcule 

objet a,b// comme il ya 2 objet a et b 

a += b;// calcule

et l'operator+= 

class::operator+=(bjet const& a)

pourquoi l'operator prend q'une seul valeur en entrée ?

  alors que elle est souvent appeler sur deux objet 

1 juin 2015 à 16:04:04

Parce que c'est une fonction membre, alors le "premier paramètre" c'est this.

-
Edité par markand 1 juin 2015 à 16:04:26

l'azerty est aux dispositions ce que subversion est aux SCM
1 juin 2015 à 16:05:28

Salut,

si c'est une fonction membre l'opérande de gauche est implicite qui est: *this, donc il ne restera que l'opérande de droite qu'on passe en argument.

si la fonction est libre alors le prototype prendra deux arguments vu qu'il y en a pas d'implicite.

-
Edité par Dichotoman 1 juin 2015 à 16:06:00

3 juin 2015 à 0:02:42

Bonjour !

je voulais juste ajouter quelques précisions à la réponse du dessus, pour les operators un peu particuliers !

En particulier operator<<, qui retourne un std::ostream (dans sa version surchargée pour être injectée dans un flux (par exemple : std::cout))

qui lui ne peut pas être un membre de la classe, car l'objet modifié est un flux !

Exemple :

std::cout << monObjet;

dans ce cas, le premier paramètre de << est un std::ostream&, le second ton objet.

c'est pour ça que le profil de l'operator<< est :

std::ostream& operator<< (std::ostream& lhm, const Object & rhs);

voire

friend std::ostream& operator<< (std::ostream& lhs, const Object & rhs);

si l'on veut que l'operator<< puisse directement se comporter comme un membre de la classe Object. Après, c'est à voir pour le développeur, veut-il contourner l'encapsulation ou pas. C'est un autre débat.

-
Edité par Helheim 3 juin 2015 à 0:41:39

4 juin 2015 à 9:55:48

Lu'!

Il ne faut pas voir friend comme un moyen de contourner l'encapsulation, mais au contraire comme un moyen de la renforcer. Si on a une fonctionnalité qui doit pouvoir agir avec notre classe, mais que pour cela elle a besoin d'accéder aux éléments privés de celle-ci, on a trois (EDIT : ben oui, trois pas deux) choix :

  • lui laisser les accès avec friend,
  • lui fournir des fonctions membres publiques pour obtenir les informations voulues,
  • faire une fonction membre implémentant la même fonctionnalité pour déléguer.

Dans le premier cas, on implémente notre fonction, c'est la seule exception au caractère privé des données.

Dans le second cas, on est probablement dans le pire scénario : on va créer un ensemble de fonctions dont on n'avait pas besoin, qui généralement seront de getters (pauvre Demeter), on dévoile le fonctionnement interne de la classe à tout le monde, avec des fonctions qui seront accessibles par tous, alors qu'on ne voulait que fournir un accès à une fonction particulière.

Dans le dernier cas, on implémente notre fonction, puis on en implémente une deuxième qui est en fait la même fonctionnalité mais déléguée à la classe, on s'est déjà rajouté du boulot pour rien. Le résultat c'est qu'on a enrichit l'interface de notre classe (si on fait ça pour chaque fonction friend, ça va vite être un joyeux merdier), avec des fonctions qui existent maintenant en deux exemplaires (typique : ostream<<(ostream, type) + type::print(ostream)). Pour l'utilisateur de la classe, c'est horrible : on se retrouve avec deux fonctions qui semblent faire la même chose, mais on n'est pas sûr, faut aller voir la doc, c'est chiant, etc, et en plus on se retrouve avec une classe qui a plein de responsabilités : viol du SRP.

Non, dans l'ordre : le plus horrible c'est le panel de getters (sauf s'ils sont cohérents avec la classe), ensuite la délégation et finalement la fonction friend. friend nous permet de maintenir la même encapsulation sans violer le SRP.

-
Edité par Ksass`Peuk 4 juin 2015 à 10:19:49

Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
4 juin 2015 à 15:24:49

les gars une autre question 

ZFraction& ZFraction::operator+=(ZFraction const& autre)
{
    m_numerateur = autre.m_denominateur * m_numerateur + m_denominateur * autre.m_numerateur;
    m_denominateur = m_denominateur * autre.m_denominateur;

    return *this;    
}

Pourquoi dans l'implantation de l'operator+= il ya le (*)   alors que c'est le symbole de l'operator de multiplication ?

4 juin 2015 à 15:29:59

Parce que mathématique. 1/2+3/4 = 10/8. C'est comme ça, c'est la vie.

Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
4 juin 2015 à 22:31:03

et c'est quoi mathématiques :o non je blague :D
5 juin 2015 à 16:51:49

Salut,

bVbrick a écrit:

les gars une autre question 

ZFraction& ZFraction::operator+=(ZFraction const& autre)
{
    m_numerateur = autre.m_denominateur * m_numerateur + m_denominateur * autre.m_numerateur;
    m_denominateur = m_denominateur * autre.m_denominateur;

    return *this;    
}

Pourquoi dans l'implantation de l'operator+= il ya le (*)   alors que c'est le symbole de l'operator de multiplication ?

Parce que tu peux vouloir additionner deux fractions de deux manières différentes :

En récupérant le résultat dans une troisième fraction, sous une forme proche de

ZFraction premier{1,2};
ZFraction second{3,4};
ZFraction resultat = premier + second; // result == 10/8
// !!! premier vaut toujours 1/2 et second vaut toujours 3/4 !!!

qui va utiliser l'opérateur + (implémenter sous la forme d'une fonction libre prenant deux ZFractions comme argument), sans modifier la valeur des éléments utilisés pour obtenir le résultat.

Mais tu peux aussi envisager d'écrire un code proche de

ZFraction premier{1,2};
ZFraction second{3,4};
premier += second; // premier == 10/8
//!!! la valeur de premier a changé !!!

Pour que ce code fonctionne, tu dois implémenter l'opérateur += sous la forme d'une fonction membre de ta classe ZFraction et qui aura pour résultat de modifier l'opérande de gauche de l'opérateur +=

Typiquement, lorsque l'on définit l'opérateur +=, il renvoie une référence sur l'objet qui a été modifié (simplifions : une référence sur l'objet qui se trouve à gauche de l'opérateur).  Or, cet objet est l'objet au départ duquel on appelle la fonction en question (un opérateur n'est jamais qu'une fonction "particulière" dans le sens où elle a une forme bien précise ;) ) et, comme il s'agit d'une fonction membre, elle dispose implicitement d'un pointeur sur l'objet au départ duquel elle est appelée: le pointeur this.

Et comme this est un pointeur, il représente l'adresse mémoire à laquelle se trouve l'objet au départ duquel on a appelé la fonction.  Or nous ne voulons pas récupérer un pointeur, mais une référence.  Nous ne devons donc pas renvoyer this, mais bien "ce qui se trouve à l'adresse représentée par this" ou, si tu préfère "ce qui est pointé par this".  Et ça, cela s'obtient avec l'étoile '*' qui, dans ce cadre bien particulier, n'a absolument rien à voir avec la multiplication : c'est ce que l'on appelle un opérateur de déréférencement (comprend : qui permet d'accéder à ce qui est pointé par un pointeur ;) )

Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
15 juin 2015 à 15:17:35

a oui c'est un peut difficile mais je vais faire avec merci

Operator

× 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.
  • Editeur
  • Markdown