Partage
  • Partager sur Facebook
  • Partager sur Twitter

Instance de classe A dans classe B

Une méthode de classe et la lecture des attributs de cette classe

Anonyme
22 juin 2017 à 10:22:33

Bonjour MichelBillaud

Excellent analyse.

Mais il faudrait savoir. Lorsque j’utilise cette formulation je me fais taquer. Quand j’illustre par un programme dont les noms de classes et de variables ne conviennent pas genre pierres de Poucet, je suis invité à être plus clair. En résumé au lieu de se pencher sur le fond on s’arrête à la forme. Et encore je passe sur les interventions dont les propos dénotent l’ aspect immature de l’intervenant. J’ai l’impression d’être Galilée toute raison gardée.

Merci de ce retour à la source c’est exactement ça, complété par une question :

Pourquoi lorsque lorsque j’accède à » m_x » par « m_a.get » j’obtiens en retour « m_a ». ?

Au fait , au cas où ça aurait une incidence , « A m_a » est aussi private :.

C’est vrai qu’il fait chaud mais pour moi aussi.

Merci.

  • Partager sur Facebook
  • Partager sur Twitter
22 juin 2017 à 10:40:23

On est trolldi ?

Pourquoi lorsque lorsque j’accède à » m_x » par « m_a.get » j’obtiens en retour « m_a ». ?

Non, vous obtenez "this.m_a.m_x".

class A  {
public :
   int m_x;        // pas besoin de plus
   A(int x = 10):m_x{x}{};
};
 
class B {
public :
   A m_a;          // une instance de A
   B():m_a{20}{};
};

...
A myA;
B myB;
int toto = myA.m_x
int titi = myB.m_a.m_x


"toto" est égal à 10 et "titi" est égal à 20.

-
Edité par bacelar 22 juin 2017 à 16:04:15

  • Partager sur Facebook
  • Partager sur Twitter
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
22 juin 2017 à 10:46:49

Le meilleur moyen pour que tu trouves les reponses à tes questions:

1) Utilise un debuggeur.
2) Execute ton programme en mode pas à pas.
3) Espionne les variables.

  • Partager sur Facebook
  • Partager sur Twitter
22 juin 2017 à 14:08:32

Parmenide a écrit:

Merci de ce retour à la source c’est exactement ça, complété par une question :

Pourquoi lorsque lorsque j’accède à » m_x » par « m_a.get » j’obtiens en retour « m_a ». ?

Tout ce que je peux dire sur get, c'est qu'il n'y en a pas dans l'exemple. Donc aucune réponse possible.

-
Edité par michelbillaud 22 juin 2017 à 14:11:18

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
22 juin 2017 à 23:04:29

Bonjour Koala

Je viens de lancer ton programme. Il est indéniable que tu as fait le tour des possibilités et qu'il est lisible même pour un amateur.
J'ai rajouté des retours de lignes pour améliorer la lisibilité des résultats.
 J'ai deux questions et à te faire part d'une observation.

Questions :- est-il possible de transmettre sur le site une copie (photo) de la console ?. Tu pourrais jauger toi même les résultats.
               - as-tu testé mon dernier envoi ?

Observation : il me semble dans une première approche que les résultats correspondent aux bonnes données. Il y a toutefois ce qui pour

moi semble curieux. Tous les retours de résultats "return laValeur"  et "return lAge" donnent lieu à l'édition d'un "cout" comme prévu dans

le programme, avec les commentaires adéquats, et à un second affichage, sur la ligne suivante, lui sans commentaire. 

                                   Exemple:  lAgeDuCapitaine() renvoie    54
                                                 54

Si j'avais l'esprit scientifique je dirais que pour vérifier la validité d'un résultat il est préférable et même essentiel de le faire dans les

mêmes conditions.

Je commence à me demander si ce n'est pas l'IDE qui fait la tête. Seule l'utilisation de ma mouture dans une autre IDE pourrait apporter

une réponse.

Merci

  • Partager sur Facebook
  • Partager sur Twitter
23 juin 2017 à 10:56:10

Parmenide a écrit:

Observation : il me semble dans une première approche que les résultats correspondent aux bonnes données. Il y a toutefois ce qui pour

moi semble curieux. Tous les retours de résultats "return laValeur"  et "return lAge" donnent lieu à l'édition d'un "cout" comme prévu dans

le programme, avec les commentaires adéquats, et à un second affichage, sur la ligne suivante, lui sans commentaire. 

                                   Exemple:  lAgeDuCapitaine() renvoie    54
                                                 54

Si j'avais l'esprit scientifique je dirais que pour vérifier la validité d'un résultat il est préférable et même essentiel de le faire dans les

mêmes conditions.

Je commence à me demander si ce n'est pas l'IDE qui fait la tête. Seule l'utilisation de ma mouture dans une autre IDE pourrait apporter

une réponse.

Merci

Ben non, c'est pas l'IDE.

Le programme execute la ligne suivante:

std::cout<<cap1.lAgeDuCapitaine()<<"\n";

Soit l'affichage du resultat de la fonction lAgeDuCapitaine() de l'instance cap1.
Pour obtenir le resultat, la fonction est executée:

int Utilisateur::lAgeDuCapitaine() const{
    std::cout<<"lAgeDuCapitaine() renvoie "<<lAge<<"\n";
    return lAge;
}

On voit que la fonction provoque un affichage avant de retourner la valeur.
Donc ce "double affichage" est normal (l'affichage de la fonction, suivit du resultat de la fonction).

Tu aurais vu cela si tu avais executé ton programme en pas à pas...

Programmer, c'est bien, avec les bon outils, c'est mieux !

  • Partager sur Facebook
  • Partager sur Twitter
23 juin 2017 à 19:04:20

Parmenide a écrit:

Bonjour Koala

Je viens de lancer ton programme. Il est indéniable que tu as fait le tour des possibilités et qu'il est lisible même pour un amateur.

Ah, tu vois? c'était le principal objectif de cet exemple ;)

Si même toi, un amateur ne connaissant "rien" (ou peu s'en faut) au développement, arrive à lire un code, c'est que le code est (vraiment) bien écrit ;)

Et c'est bel et bien la preuve que, même sans utiliser de jargon, il est tout à fait possible d'écrire un code qui ... exprime clairement nos intetion ;)

Blisinger signifie le feu. C'est le feu. Le mot c'est la chose. Connais le mot et tu maîtrise la chose

-- Eragon, 2006

J'ai rajouté des retours de lignes pour améliorer la lisibilité des résultats.
 J'ai deux questions et à te faire part d'une observation.

Questions :- est-il possible de transmettre sur le site une copie (photo) de la console ?. Tu pourrais jauger toi même les résultats.

Tout est possile! Mais je ne le ferais pas...

Utilise la balise code, quitte à choisir "bash" au lieu de C++ pour montrer l'affichage que tu obtiens ;)

- as-tu testé mon dernier envoi ?

non

Observation : il me semble dans une première approche que les résultats correspondent aux bonnes données. Il y a toutefois ce qui pour moi semble curieux. Tous les retours de résultats "return laValeur"  et "return lAge" donnent lieu à l'édition d'un "cout" comme prévu dans

le programme, avec les commentaires adéquats, et à un second affichage, sur la ligne suivante, lui sans commentaire.

Exemple:  lAgeDuCapitaine() renvoie    54

Si j'avais l'esprit scientifique je dirais que pour vérifier la validité d'un résultat il est préférable et même essentiel de le faire dans les mêmes conditions.

C'est peut-être parce qu'il n'y avait aucune approche scientifique dans cet exemple ;)

Le but de cet exemple uniquement de démontrer certains points au sujet desquels nous nous heurtions.

Il est clair que la très grosse majorité de ce code n'apparaitrait au grand jamais dans un de mes codes de production, et ce, pour une série de raisons ;)

Si de nombreux affichages ont lieu dans les différentes fonctions, c'est "uniquement" pour qu'il te soit possible de suivre, l'exécution "pas à pas" et donc de constater ce qui est fait à quel endroit

Mais, surtout, cette exemple avait pour but de démontrer l'importance de nommer correctement les éléments que l'on utilise (quels qu'ils soient).

Et je crois avoir atteint mon objectif, sur ce coup ;)

  • Partager sur Facebook
  • Partager sur Twitter
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
Anonyme
24 juin 2017 à 9:12:43

Pas de message de Koala

Un bonjour général :je pense qu’il est nécessaire de faire une mise au point à l’attention des intervenants.

Par principe je postule la sincérité de vos interventions. Je vous invite pourtant à respecter le mode opératoire suivant :

polarisez votre attention sur le programme élémentaire que j’ai écrit en première réponse à Koala. Ilne peut être plus simple. Si les termes utilisés pour désigner les classes et les deux variables ne vous conviennent pas rien ne vous empêche de les réécrire en chinois, sous forme de lettres de l’alphabet, d’idéogrammes ou de runes si le cœur vous en dit et si compilateur l’admet . Dès l’instant où vous en respectez l’esprit , vous le lancez.

Soit les deux résultats sont égaux et correspondent à la valeur d’initialisation de la variable accédée soit ils ne le sont pas. Dans les deux cas vous devriez être à même d’en tirer les bonnes conclusions et de m’en faire part.

Inutile de faire des commentaires en dehors de ce mode opératoire. Ils n’ont pas d’autre résultat que de dévaloriser le sérieux et la raison d’être de ce site.

Pour terminer j’ajouterai que si j’avais à recruter l’un d’entre vous , ce qui n’est pas le cas, le seul sur lequel porterait mon choix est Koala pour la simple raison qu’il a été jusqu’à maintenant le seul à tenter une explication.

Il y a un problème qui n’est pas de mon fait que vous le vouliez ou non. Il est sans doute plus difficile à cerner qu’une affaire de point-virgule raison pour laquelle il semble vous échapper.

En dehors de ce mode opératoire passez votre chemin vos interventions sont inutiles. Je n’ai pas moi non plus de temps à perdre.

Merci.

A l’attention de Koala

Merci de ton programme. Mais je dois te préciser après examen que les résultats obtenus ne sont pas en mesure de confirmer ou d’infirmer ceux que je prétends. S’il y avait un cahier des charges je dirais que tu ne l’as pas respecté. A protocole différent résultats différents. Comme tu as pris en considération ma demande je te donne une amorce de piste même si débutant mon avis ne fait pas autorité. Les deux classes aussi bien dans ton programme que dans le mien ne sont pas indépendantes et il serait bien que tu fixes ton attention sur les constructeurs du mien..

A+

  • Partager sur Facebook
  • Partager sur Twitter
24 juin 2017 à 11:25:41

Parmenide a écrit:

J'ai sans doute mal assimilé les quelques notions que j'ai acquises pour ne pas avoir compris que sous deux termes différents, type et
valeur, on trouve la même chose.

Je pense que ce qui te bloque c'est peut-être cela. En aucun cas type et valeur ne sont les même choses.
Si je dis "x est de type int, il contient la valeur 3". Le nombre 3 est un int, le nombre 3 est dans x, x est une instance de type int. Par abus on dit "x vaut 3" mais c'est un raccourci trompeur. Ces 3 choses : int, 3 et x sont différentes. Ça n'a pas de sens de dire "je met 3 dans int ou int c'est 3".
Dans ton code les types sont int, Avant et Arriere. Les instances sont temp, tante, tante.m_mot, temp.m_age, tante.m_mot.m_ageet std::cout. Seules les instances contiennent quelque chose.
  • Partager sur Facebook
  • Partager sur Twitter

En recherche d'emploi.

24 juin 2017 à 12:01:36

Je crois que ce qui le bloque, c'est qu'il ne cherche pas à comprendre les explications qui lui ont déjà été données, tout occupé qu'il est à jouer au cheffaillon qui distribue les bons points à des intervenants dissipés.

Allons y calmement, on peut réduire le problème à ces deux définitions de classes :

class A {
private:
    int m_x;
public :
    A(int x) : m_x(x) {}
    int foo() const { return m_x; }
};

class B {
private:
    A m_a;
public:
    B()   : m_a(88) {}
    int bar() const { return m_a.foo();  }
};


et à la question : pourquoi le code suivant

int main()
{
    A a(55);
    B b;
    cout << a.foo() << " different de " << b.bar() << endl;
    return 0;
}


affiche t'il que 55 est différent de 88.  Ce qui est  évident :

  • la premiere fonction (foo) retourne la valeur de l'entier présent dans a, qui a été initialisé à 55
  • la seconde retourne celle de l'entier présent dans la donnée m_a de b, entier qui été mis à 88 par la liste d'initialisation dans le constructeur.

EDIT: maintenant, si on en est à s'embrouiller au niveau des concepts de type, donnée et variable, c'est peut être pas une bonne idée d'y rajouter la notion de classe.

-
Edité par michelbillaud 24 juin 2017 à 16:59:30

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
25 juin 2017 à 9:10:01

De chefaillon à Monsieur billaud

« Un quart d’heure avant sa mort mossieur billaud vivait encore »

Ton évidence n’est pas évidente mais parait évidente. Il suffit pour s’en convaincre, sans rien toucher d’autre, de donner à « x » de « m_x(x) » une valeur constante. « 99 » par exemple pour que tu comprennes.

Le résultat est alors celui demandé à savoir en retour et dans les deux cas, la valeur de m_x et non celle de m_x et de m_a.

L’hypothèse selon laquelle « la seconde retourne celle de l’entier dans la donnée m_a de B «  est d’une évidence farfelue. En tout état de cause elle ne répond pas à ce qui est demandé.

  • Partager sur Facebook
  • Partager sur Twitter
25 juin 2017 à 11:20:39

Un peu de rigueur ne pourrait pas faire de mal.

  • quand tu dis "le résultat", de quoi tu parles ?
  • quand tu parles de "donner à x une valeur constante", montre le code. Ca évite de parler dans le vide.

Peut être que tu te comprends quand tu écris ça, mais bon rappelles-toi quand même que c'est toi qui as des problèmes avec ton propre code. Il y a peut être une raison.

"La" valeur de m_x, il y en a deux

  • celle qui est une donnée membre de la variable a (de type A) définie dans le main (soit a.m_x, si on pouvait y accéder directement, ce qu'empêche l'attribut private)
  • celle qui est contenue dans la donnée membre m_a de l'instance b du main, soit b.m_a.m_x.

Les fonctions foo et bar sont là, précisément, pour retourner les valeurs des "m_x", dans le cas des deux classes.

 Et si tu n'as pas de réponse "à ce qui est demandé", tu peux te poser la question de la formulation que tu emploies.

-
Edité par michelbillaud 25 juin 2017 à 11:29:19

  • Partager sur Facebook
  • Partager sur Twitter
25 juin 2017 à 14:35:54

Parmenide a écrit:

Inutile de faire des commentaires en dehors de ce mode opératoire. Ils n’ont pas d’autre résultat que de dévaloriser le sérieux et la raison d’être de ce site.

En fait, il faut savoir que les gens qui répondent sur ce site, le font parce qu'ils ont envie de passer du temps à le faire. Donc chacun à ses propres objectifs et si tu ne veux pas lire leur point de vue, libre à toi de ne pas le faire, mais tu ne peux pas leur interdire de l'exposer s'il n'est pas hors des règles du forum.

Quant à parler du sérieux de ce site, le cours de C++ qu'il y a sur cette plateforme est décrié par tous les intervenants qui comprennent vaguement quelque chose à C++ depuis plusieurs années déjà parce qu'il est blindé à craquer de conneries et qu'il apprend à faire n'importe quoi avec ce langage (sans parler des notions qui sont utilisées complètement n'importe comment, ce qui en résulte étant des codes d'exemples pourris de bugs). Alors parler de leur sérieux, ça fait doucement rigoler (jaune).

  • Partager sur Facebook
  • Partager sur Twitter

Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

Anonyme
26 juin 2017 à 10:23:10

Bonjour à vous.

C’ est vrai que je ne me sens pas à l’aise dans la formulation du langage. C’est la conséquence d’un apprentissage solitaire. Mais lorsque j’écris « donner à « x » de « m_x(x) » une valeur constante. « 99 » » c’est assez clair, non ? , il suffit, sans se poser de question, de remplacer « x » par « 99 ». Le résultat est qu’au lieu d’avoir en retour deux valeurs différentes, on a deux mêmes valeurs identiques à celle d’initialisation de « m_x ».

Quant aux intervenants je salue leurs intentions, mais leurs interventions peuvent s’affranchir de jugements de valeur, d’un ton parfois presque méprisant, et même de termes grossiers, etc ,en fait se borner à venir en aide à celui qui la demande. Et pour cela, la moindre des choses est de prendre connaissance en préalable à toute réponse, de la nature de l’obstacle rencontré par celui qui demande une aide et de ne pas se contenter de faire simplement étalage avec morgue de leur science parfois d’ailleurs entachée d’inexactitudes.

Je vous livre mon ressenti, il est tout frais.

Quant à la qualité du c++ mon inexpérience de la programmation ne me permet pas de juger et de toute façon ce n’est pas mon propos.

Pour en venir au cœur du sujet je vous donne mon explication en utilisant le squelette de Michaud. (le squelette de programme bien sûr !.)

class A {

private:

int m_x;

public :

A(int x) : m_x(x) {}

int foo() const { return m_x; }

};

class B {

private:

A m_a;

public:

B(): m_a(88) {}

int bar() const { return m_a.foo();}

};

Pour la compréhension de ma question de départ, étant donnée la différence de formulation du langage que j’utilise, je reviens sur mon interrogation

 :

nune instance de classe peut-elle avoirs accès en toutes circonstances aux membres données de sa classe par l’intermédiaire d’une méthode membre de cette classe. ?

Je précise par clarté, que je distingue deux catégories d’appels du Main, celle qui sollicite directement une classe, la classe A par exemple ( une méthode de la classe pour les pointilleux), et celle qui sollicite la même classe par l’intermédiaire de la classe B , cette dernière accédant à la classe A par le biais de l’instance de la classe A  sous la forme implicite « m_a.bar() » qui en retour doit renvoyer dans B, la valeur de « m_x » sous la forme « ma_foo() ».

Selon moi :

-lorsque Main appelle A directement il n’y a pas de problème c’est bien la valeur de « m_x(x) » au moment de l’appel qui est renvoyée. Les deux résultats dans le main sont identiques.

-lorsque Main appelle A par l’intermédiaire de la classe B :

le constructeur de B initialise « m_a »,

puis, lors de l’appel de A , «  m_a.bar() »,

le constructeur de A étant sous la forme A(int x) : m_x(x) ; (initialisation par copie) celui de B délègue à celui de A la valeur d’initialisation de « m_a ». C’est cette valeur qui est obtenue en retour et non celle de « m_x ». Les deux résultats supposés de « m_x » obtenus dans le main sont différents.

lorsque « m_x » est initialisée par valeur, 99 par exemple, le constructeur de B n’est plus en condition de déléguer, et les deux valeurs de retour sont identiques. Dans les deux cas on obtient bien la valeur de « m_x » les deux résultats obtenus dans le main sont identiques.

Si vous souhaitez donner votre avis motivé je suis preneur. Mais pour ma part la conclusion est qu’il existe au moins un cas où une instance de classe peut ne pas avoir accès aux membres données de sa classe, privées ou public.( non je ne suis pas anti POO).

Je ne sais pas si en programmation on rencontre souvent un tel usage d’une instance de classe, mais si c’est le cas, c’est une ouverture vers le « bug » pour qui se fie aveuglément à la doctrine et qui dit bug dans un programme technique……

J’espère avoir été assez clair non ?

Au fait il est indéniable que je suis maintenant aligné sur le mode «has been » mais je pense que dire bonjour lors d’une intervention n’est pas au-dessus des forces des intervenants. Ah ! ces vieux !

Merci de votre compréhension.

  • Partager sur Facebook
  • Partager sur Twitter
26 juin 2017 à 10:55:52

BONJOUR (oui je crie, rapport à mon sonotone de vieux gâteux).

Je pense que vous n'avez toujours pas compris la différence entre une classe et un objet (ou instance de classe).

On va prendre un exemple bien plus simple :

int main()
{
    A a1(55);
    A a2(66);
    cout << a1.foo() << " different de " << a2.foo() << endl;
    return 0;
}



  • Partager sur Facebook
  • Partager sur Twitter
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
26 juin 2017 à 11:10:01

Parmenide a écrit:  Mais lorsque j’écris « donner à « x » de « m_x(x) » une valeur constante. « 99 » » c’est assez clair, non ? , il suffit, sans se poser de question, de remplacer « x » par « 99 ».


Il se trouve que non, ce n'est pas clair du tout. Il faut être totalement explicite, c'est à dire montrer le code qui est censé le faire, intégralement.

C'est justement pour ne pas avoir de question à se poser sur l'objet précis de la discussion; à partir de quoi on peut parler de la même chose.

Vous parlez de << prendre connaissance en préalable à toute réponse, de la nature de l’obstacle rencontré par celui qui demande une aide >>, c'est bien de ça qu'il s'agit, quand on vous demande d'être précis vous y opposez de bizarres résistances.

Quand vous dites << ma conclusion est qu'il il existe au moins un cas où une instance de classe peut ne pas avoir accès aux membres données de sa classe >>, allez-y, montrez le code. Le code complet qui le démontre. Il n'y a a que ça qui pemettra de confirmer ou démentir la conclusion, et éventuellement, si le raisonnement est buggé, de trouver d'où vient la mauvaise conception sous-jacente.

-
Edité par michelbillaud 26 juin 2017 à 11:13:58

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
27 juin 2017 à 9:13:20

Bonjour Messieurs Bacelar/Billaud

Désolé pour le sonotone. Mais j’ai ouï dire qu’utiliser des mots en majuscules était injurieux. Bien sûr je n’en crois rien.

Merci bacelar de tes efforts pour m’inculquer une notion que je connais déjà. Je profite de ton embryon de programme pour te poser une question. Si tes deux « foo() » pointent (langage courant) sur la même variable les valeurs de retour seront selon toi différentes entre elles ou égales entre elles ?. Je te laisse le choix de la réponse. Elle pourrait être la première marche (image) sur ma voie.

Par contre ce que je ne parviens pas à assimiler c’est que vous, les sceptiques intégristes, vous avez la possibilité de vérifier sur pièce ce que j’avance, en vous donnant la peine de recopier le dernier programme élémentaire que j’ai posté sur le site il y a quelques jours et en l’exécutant et que vous vous en abstenez…sans autre commentaire. J’ai rajouté ici à la fin celui du sieur Billaud tout aussi probant une fois complété et exécuté. Exécutez-le s’il vous paraît plus clair.

Les valeurs de retour sont ce qu’elles sont et vous ne pouvez les contester.

Bonjour MichelBillaud

Si tu trouves que ton code n’est pas assez explicite il te faut t’en prendre à toi-même. Comprends-toi d’abord toi-même.

PS : il pleut un peu,, comme je suis sympa, enfin j’espère, je te renvoie ton code, documenté à ta façon, dont les résultats confirment ce que j’avance. Tu ne devrais avoir aucune difficulté à te comprendre. La seule rectification de mon cru est le point d’interrogation dans le « cout » du Main. Sa présence objective est ici fondamentale.

// Main

-------------------------------------------

#include <iostream>

#include "A.h"

#include "B.h"

int main()

{

A a(55);

B b;

a.foo();

b.bar();

std::cout<<a.foo()<< " different ? de " << b.bar()<<"\n\n";

return 0;

}

// A.h

---------------------------------------------

#ifndef A_H_INCLUDED

#define A_H_INCLUDED

class A

{

public:

A(int x);

int foo() const;

private:

int m_x;

};

#endif // A_H_INCLUDED

//A.cpp

------------------------------------------

#include <iostream>

#include "A.h"

A::A(int x): m_x(x)

{ }

int A::foo() const

{

return m_x;

}

// B .h

----------------------------------------------

#ifndef B_H_INCLUDED

#define B_H_INCLUDED

#include "A.h"

class B

{

public:

B();

int bar() const;

private:

A m_a;

};

#endif // B_H_INCLUDED

//B.cpp

----------------------------------------------

#include<iostream>

#include "B.h"

B::B() : m_a(88)

{}

int B::bar() const

{

return m_a.foo();

}

La réponse dans le Main est « OUI » quand on poseA::A(int x) : m_x(x) ; et « NON » quand on pose A::A(int x) : m_x(99) ; Nota : 99 est une valeur de typepifométrique.

Comme il s’agit ici dans les deux retours d’obtenir la seule et unique valeur d’initialisation de l’attribut «  m_x » lorsque les deux valeurs de retour diffèrent c’est qu’il y a hiatus entre le vrai et ce qui est obtenu. Ici la différence dans les valeurs traduit un résultat erroné et non une preuve de la validité des résultats.

CQFD .

L‘expérience est une lanterne qu’on porte dans le dos.

A++

  • Partager sur Facebook
  • Partager sur Twitter
27 juin 2017 à 10:54:22

Parmenide a écrit:

La réponse dans le Main est « OUI » quand on poseA::A(int x) : m_x(x) ; et « NON » quand on pose A::A(int x) : m_x(99) ; Nota : 99 est une valeur de typepifométrique.

Comme il s’agit ici dans les deux retours d’obtenir la seule et unique valeur d’initialisation de l’attribut «  m_x » lorsque les deux valeurs de retour diffèrent c’est qu’il y a hiatus entre le vrai et ce qui est obtenu. Ici la différence dans les valeurs traduit un résultat erroné et non une preuve de la validité des résultats.

Merci ce code, qui est absolument parfait, pour une fois ;-)  (mais pourquoi l'étaler sur 5 fichiers, hein ? vous comptez faire une bibliothèque et le réutilliser dans de nombreuses applications ?)

Aucun résultat erroné. Hiatus, mon oeil. Il n'y a d'erreur, ou de hiatus, qu'en tant que différence entre un résultat voulu, et un résultat obtenu. Ici, pas de description de ce qu'on attendrait, donc on se borne à constater ce qu'on obtient quand on fait tourner le programme.

Il se trouve que qie programme fait exactement ce qui est écrit, et ce qui est obtenu  est complètement prévisible à partir des règles qui définissent la sémantique opérationnelle du langage  (tant qu'on n'a pas écrit de code avec des UB, autre sujet).

Quand le constructeur de A est celui-ci

A::A(int x)              // version 2
   : m_x(99) 
{}

il ne tient aucun compte de la valeur qui lui est transmise. A la différence de

A::A(int x)
   : m_x{x}              // version 1
{}

Dans la version 2, toutes les instances de A sont donc initialisées de la même façon. Il n'est donc pas étonnant que a.foo() et b.bar() retournent la même valeur, puisque foo va chercher la valeur du m_x de a (directement) et que bar demande à la donnée membre de m_a, qui est aussi une instance de A, de lui indiquer la valeur du m_x.

Dans la version 1, l'instance a est initialisée explicitement à 55, et celle qui est contenue dans b, à 88.

Aucun problème là dedans. A part, justement, de tenir absolument à y voir un problème.

 - o - 0 - o -

Il me semble, mais je peux me tromper, à partir de la phrase << Comme il s’agit ici dans les deux retours d’obtenir la seule et unique valeur d’initialisation de l’attribut «  m_x » lorsque les deux valeurs de retour diffèrent  ...>> que la cause est une fausse conception de la notion d'instance et de membre, déjà signalée.

  L'attribut m_x, avec un article défini, il y en a un par objet de la classe A,  et celui de la variable a _n'est pas_ celui contenu dans la donnée membre b.m_a. Les objets a et b.m_a sont du même type (classe A), mais ce sont des instances différentes, situées à un endroit différent en mémoire, et susceptibles de contenir des valeurs différentes.

 - o - O - o -

Par contre, en revanche, néanmoins et cependant, je n'arrive absolument pas à voir le lien avec votre conclusion tranchée des messages précédents

<< ma conclusion est qu'il il existe au moins un cas où une instance de classe peut ne pas avoir accès aux membres données de sa classe >>

vous pouvez expliquer ?  Quelle instance n'a pas accès à quelle donnée membre ?

-
Edité par michelbillaud 27 juin 2017 à 11:18:46

  • Partager sur Facebook
  • Partager sur Twitter
27 juin 2017 à 10:54:38

Salut

Je me permets d'intervenir, je sens que les esprits s'échauffent, on va repartir de 0.

Je dois avouer avoir beaucoup de mal a comprendre la discussion et ce qui ne va pas. Du coup, je reprends le dernier code, le met en forme et je l'exécute sur Coliru.com :

#include <iostream>

class A {
 public:
  A(int x);
  int foo() const;

 private:
  int m_x;
};

A::A(int x) : m_x(x) {}

int A::foo() const { return m_x; }

class B {
 public:
  B();
  int bar() const;

 private:
  A m_a;
};

B::B() : m_a(88) {}

int B::bar() const { return m_a.foo(); }

int main() {
  A a(55);
  B b;

  a.foo();
  b.bar();

  std::cout << a.foo() << " different ? de " << b.bar() << "\n\n";

  return 0;
}

affiche :

55 different ? de 88

C'est ok ?

Pour moi, c'est bien le résultat attendu.

Ensuite, tu écris "« NON » quand on pose A::A(int x) : m_x(99)", tu parles d'ecrire ce code donc ? :

#include <iostream>

class A {
 public:
  A(int x);
  int foo() const;

 private:
  int m_x;
};

A::A(int x) : m_x(99) {}

int A::foo() const { return m_x; }

class B {
 public:
  B();
  int bar() const;

 private:
  A m_a;
};

B::B() : m_a(88) {}

int B::bar() const { return m_a.foo(); }

int main() {
  A a(55);
  B b;

  a.foo();
  b.bar();

  std::cout << a.foo() << " different ? de " << b.bar() << "\n\n";

  return 0;
}

affiche :

main.cpp:12:10: warning: unused parameter 'x' [-Wunused-parameter]
A::A(int x) : m_x(99) {}
         ^
1 warning generated.
99 different ? de 99

C'est ok ?

Pour moi, c'est aussi le résultat attendu.

Quel serait le résultat attendu ? Quel est le problème avec ce code ?

HS : dans la phase "Si tes deux « foo() » pointent (langage courant) sur la même variable". En C++ (et d'autres langages de programmation), il existe la notion de pointeur, donc le terme "pointe" a un sens particulier. Dans les codes donnés, il n'y a pas de pointeurs, et donc utiliser le terme "pointe" porte a confusion.

Parmenide a écrit:

Selon moi :

-lorsque Main appelle A directement il n’y a pas de problème c’est bien la valeur de « m_x(x) » au moment de l’appel qui est renvoyée. Les deux résultats dans le main sont identiques.

-lorsque Main appelle A par l’intermédiaire de la classe B :

le constructeur de B initialise « m_a »,

puis, lors de l’appel de A , «  m_a.bar() »,

le constructeur de A étant sous la forme A(int x) : m_x(x) ; (initialisation par copie) celui de B délègue à celui de A la valeur d’initialisation de « m_a ». C’est cette valeur qui est obtenue en retour et non celle de « m_x ». Les deux résultats supposés de « m_x » obtenus dans le main sont différents.

lorsque « m_x » est initialisée par valeur, 99 par exemple, le constructeur de B n’est plus en condition de déléguer, et les deux valeurs de retour sont identiques. Dans les deux cas on obtient bien la valeur de « m_x » les deux résultats obtenus dans le main sont identiques.

Si vous souhaitez donner votre avis motivé je suis preneur. Mais pour ma part la conclusion est qu’il existe au moins un cas où une instance de classe peut ne pas avoir accès aux membres données de sa classe, privées ou public.( non je ne suis pas anti POO).

Je ne sais pas si en programmation on rencontre souvent un tel usage d’une instance de classe, mais si c’est le cas, c’est une ouverture vers le « bug » pour qui se fie aveuglément à la doctrine et qui dit bug dans un programme technique……

J’espère avoir été assez clair non ?

Si je comprends bien, tu dis que dans le premier cas (avec le code "m_x(x)"), les 2 valeurs affichent sont identiques. Dans le second cas (avec le code "m_x(99)"), les 2 valeurs sont identiques.

Ca, c'est ok.

Par contre, les explications ne sont pas correctes a priori (si je comprends bien). Dans les deux cas, la processus est le même, seule la valeur utilisée pour initialiser m_a change.

Dans le main, quand tu crées l'objet de type B, cela appelle le constructeur par défaut de B. Lors de la construction, un objet A est construit lors de l'initialisation de la variable membre m_a. Le constructeur de A avec un paramètre int est appelé, avec la valeur 88. Dans le constructeur de A, la variable m_x est initialisée avec le paramètre x, donc la valeur 88. Quand tu appelles A::foo(), cela affiche la valeur de m_x, donc 88.

Dans le main, quand tu crées l'objet de type A avec la valeur 55, cela appelle le constructeur de A qui prend un int en parametre. Le constructeur de A initialise la variable membre m_x avec la valeur passée en paramètre, donc la valeur 55. Quand tu appelles A::foo(), cela affiche la valeur de m_x, donc 55.

Jusque la, on est d'accord ? Cela affiche 2 valeurs différentes parce que les valeurs de m_x contenues dans les variables a et b sont différentes.

Quand tu remplaces "m_x(x)" par "m_x(99)", le processus est le meme, sauf que m_x n'est plus initialisée avec la valeur x passee en parametre, mais avec la valeur 99.

Donc, quand tu appelles a.foo() et b.bar() dans le main, cela affiche les valeurs des variables membres m_x contenus dans les variables a et b, qui contiennent la même valeur 99.

Est-ce que c'est plus clair ?

  • Partager sur Facebook
  • Partager sur Twitter
27 juin 2017 à 11:12:53

Je crois que j'ai compris le problème:

int main()
{
   int a{12};
   int const * pa = &a;

   int b{24};
   int const * pb = &b;

   std::cout << "a: " << a << " pa: " << pa << std::endl;
   std::cout << "b: " << b << " pb: " << pb << std::endl;

   a = b;

   std::cout << "a: " << a << " pa: " << pa << std::endl;
   std::cout << "b: " << b << " pb: " << pb << std::endl; 

   b = 48;

   std::cout << "a: " << a << " pa: " << pa << std::endl;
   std::cout << "b: " << b << " pb: " << pb << std::endl; 

   return 0;
}

pa et pb sont des pointeurs que je fais pointer sur a et b respectivement, il contiennent respectivement l'adresse de a et b dans la mémoire de l'ordinateur. Ce que tu peux remarquer sur la première série d'affichage c'est que a et b ont bien les valeurs attendues (12 et 24). Ce que tu peux remarquer également c'est que les valeurs de pa et pb sont différentes, ce qui veut dire que a et b ne sont pas au même endroit dans la mémoire.

Après l'instruction a = b, la seconde série d'affichage indique que a a bien changé de valeur comme c'était attendu, en revanche pa et pb n'ont pas changés de valeur, il y a effectivement deux variables de type int qui contiennent la même valeur.

La dernière série d'affichage va donner une valeur de 48 pour b, alors que celle de a est restée inchangée (24), pa et pb quant à eux n'ont pas changé non plus.

a et b ont le même type, mais sont totalement indépendantes, changer la valeur de l'une n'a aucun effet sur la valeur de l'autre. Ceci est valable pour n'importe quelle variable de n'importe quel type or une classe est un type, donc si j'ai deux instances d'une même classe, elles sont totalement indépendantes. Dans ton cas la valeur que prendra la variable membre est celle qui sera passée au constructeur qui sera utilisé pour construire la variable (l'instance de la classe) .

-
Edité par int21h 27 juin 2017 à 11:18:05

  • Partager sur Facebook
  • Partager sur Twitter
Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
27 juin 2017 à 11:54:54

Dans le cas suivant:
A::A(int x) : m_x(99) {}

Il est normal que quelque soit la valeur donnée au paramètre, m_x aie une valeur de 99, puisque le paramètre est tout bonnement ignoré.

Mais, le fait que 2 instances renvoient une valeur identiques n'implique pas que ces deux instances sont identiques.
Le meilleur moyen de s'en rendre compte, est d'afficher l'adresse de m_x.

Donc, si je reprend la dernière version et que je modifie legerement:

#include <iostream>
 
class A {
 public:
  A(int x);
  int foo() const;
  const int* addr_m_x() const;
 
 private:
  int m_x;
};
 
A::A(int x) : m_x(99) {}
 
int A::foo() const { return m_x; }
const int* A::addr_m_x() const {return &m_x; }
 
class B {
 public:
  B();
  int bar() const;
  const int* addr_m_x() const;
 
 private:
  A m_a;
};
 
B::B() : m_a(88) {}
 
int B::bar() const { return m_a.foo(); }
const int* B::addr_m_x() const { return m_a.addr_m_x(); }
 
int main() {
  A a(55);
  B b;
 
  a.foo();
  b.bar();
 
  std::cout << a.foo() << " different ? de " << b.bar() << "\n";
  std::cout << a.addr_m_x() << " different ? de " << b.addr_m_x() << "\n";
 
  return 0;
}

Je n'ai ajouté que les lignes 7, 16, 22, 31 et 41.
J'obtient le resultat suivant sous cpp.sh:

99 different ? de 99
0x779282ba8d20 different ? de 0x779282ba8d30
Resultats certes identiques, mais adresses (et donc variables) différentes.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
28 juin 2017 à 11:00:54

Bonjour Messieurs

Merci de vos réponses c’est une véritable avalanche. Il me faudra du temps pour tenter de déguster toutes vos réponses et encore si je suis en mesure de toutes les comprendre. Je saurais toutefois en faire mon profit.

Sur la base du programme que Billaud qualifie de parfait mais surtout pour bien me faire comprendre, et dans la formulation de plus anciens que moi, est-ce que vous confirmez ou infirmez que :

compte tenu de l’utilisation d’une instance de classe dans les conditions précitées :

-tout porte à croire que dans la première version il n’existe aucune certitude de pouvoir préciser la valeur de m_x par les moyens utilisés (résultats différents)

-tout donne à penser que l’obtention de la valeur de m_x réside seulement dans la seconde version. (égalité des résultats).

Enfin : non M Billaud je n’ai pas l’intention de créer une bibliothèque j’en suis bien incapable, mais l’un d’entre vous a bien voulu écrire qu’ il est plus facile d’acquérir de bonnes habitudes que de se débarrasser de mauvaises. Je partage. Il ne faut pas croire que de mon passage sur ce site je ne retire rien.

Pour les fanas de la sémantique j’observerai que le langage de programmation s’est approprié des termes du langage courant et non le contraireet qu’au cas particulier du terme pointeur il est aussi utilisé dans le jeu de boules.

Pour ceux qui s’acharnent à répondre sur la forme et non sur le fond j’espère que mes explications suivantes les combleront. Je ne suis pas respectueux du langage peut-être. Mais pour moi utiliser à outrance le terme « objet » c’est adopter la nationalité schtroumpf. Une classe serait un objet qui donne naissance à un objet lequel autorise un objet de l’objet etc. Pour moi les choses sont beaucoup plus simples même s’il peut y avoir entorse. Une classe répond à des spécifications précises de forme et de fond alors une classe reste une classe. Le nom de la classe à l’extérieur de la classe est l’« objet » qui concrétise la classe et le mot associé à l’objet est l’ « instance ». A l’intérieur de la classe il n’y a que méthodes et attributs et toute autre association est à défaut de qualificatif spécifique appelé « expression ». Je me plante ?

A propos de pointeurs dans mon sujet, je me demande si leur utilisation n’est pas de nature à biaiser un résultat. Il me semble avoir lu quelque part que la présence d’une instance de classe A dans une classe B pouvait être illustrée comme l’inclusion d’une des classes dans l’autre. Comme si le propriétaire terrien d’un champ englobait le champ plus petit d’un autre propriétaire. L’utilisation de pointeurs rendrait leur autonomie aux deux champs ce qui peut avoir une incidence.

Je vous ai assez ennuyé avec mon bavardage, je vais faire la sieste. Mais oui ce n’est pas parce que cette réponse est postée le matin qu’elle est écrite le matin.

Merci.

Dans mon élan , ce n’est pas l’animal, je me concentre sur la cas Billaud ( pardon ce n’est pas volontaire !). Il est le premier de la liste et sans doute il m’est le plus accessible.

Si j’ai bien compris dans le cas N° 2, du fait que les expressions pointent ( mais oui le point serait un pointeur ?) sur l’attribut « m_x » elles copient toutes la valeur de « m_x ». Ok, en cela elles vérifient le dogme.

Dans le cas N°1, nonobstant le mode d’initialisation des deux attributs, comme dirait mon pote gendarme, bien que les expressions pointent sur l’attribut « m_x » à l’identique du cas N° 2, les résultats sont différents.

Là je sens mon esprit d’analyse mis à mal. Pourquoi un même processus donnerait dans les mêmes conditions un résultat différent ?

Sauf précisions complémentaires je reste sur ma soif.

Je crois toutefois nécessaire de compléter mon développement. La différence entre ces deux résultats a sans doute une autre origine que celle d’un constructeur qui fait la gueule et qui ne tient pas compte de la valeur d’initialisation de son attribut.. La raison d’être d’un constructeur n’est-elle pas d’initialiser les attributs ?.

L’impossibilité de vérifier que la donnée membre « m_a » est bien initialisée dans le cas N°2, tient à sa nature d’instance. Son adresse est comprise parmi celles des éléments au sens large de sa classe et à moins de connaître la méthode pour y accéder, un « cout » est impuissant.

Un élément, au sens commun du terme, intervient dans le cas N° 1. Le constructeur de « m_x » est appelé deux fois.

La première fois , lors de la création de l’objet A , disons lors de sa lecture, « m_x » est initialisé à sa valeur explicite. La seconde fois, lors de la création-lecture de l’objet B « m_x » est alors initialisé à la valeur de « m_a », différente de celle de « m_x ».

Je vous laisse à penser ce que peut représenter une variable qui à deux adresses. Je connais les adresses à plusieurs étiquettes, mais l’étiquette à plusieurs adresses c’est encore hors de mon parcours ..

La seule explication que je me donne hormis celle avancée dans mon intervention précédente est qu’il y a création, spontanée( ?) d’une copie de « m_x », la valeur de initiale de « m_x » attribut étant en réalité demeurée la même ce que semble confirmer un premier retour d’appel de « a.foo() ».

Je pourrai concevoir que l’étiquette « m_x » second correspond à une adresse qui contient l’adresse de « m_x » premier, les deux « m_x » n’en faisant en réalité qu’un, mais dans cette éventualité les deux mêmes étiquettes seraient modifiées lors du second appel par la valeur de « m_a » , ce qui n’est pas.

C’est assez long comme ça je n’irai pas au-delà.

En conclusion, selon mon approche, si les résultats différents obtenus au final sont compatibles avec ceux qui seraient obtenus dans le cas d’attributs de deux classe distinctes, sans liens communs entre elles, ils sont ici, dans le cas de classes imbriquées, en contradiction avec le dogme qui assure qu’une instance de classe peut dans tous les cas, accéder aux attributs de sa classe par l’intermédiaire d’une méthode de sa classe d’origine.

Pour moi c’est CQFD mais que suis-je ?

Papy fait de la résistance.

  • Partager sur Facebook
  • Partager sur Twitter
28 juin 2017 à 12:31:56

Parmenide a écrit:

Pour les fanas de la sémantique j’observerai que le langage de programmation s’est approprié des termes du langage courant et non le contraireet qu’au cas particulier du terme pointeur il est aussi utilisé dans le jeu de boules.

Pour ceux qui s’acharnent à répondre sur la forme et non sur le fond j’espère que mes explications suivantes les combleront. Je ne suis pas respectueux du langage peut-être. Mais pour moi utiliser à outrance le terme « objet »  [...]c’est adopter la nationalité schtroumpf. Une classe serait un objet qui donne naissance à un objet lequel autorise un objet de l’objet etc.

Les mots ont en général plusieurs sens. Ici on est dans un cadre technique bien délimité, où les termes d'objet, classe, instance, membre etc ont un sens précis, et on évite les conflits entre plusieurs significations. La notion de dent n'est pas la même chez un horloger et chez un dentiste.

> Une classe serait un objet qui donne naissance à un objet lequel autorise un objet de l’objet etc.

En C++ une classe ne donne naissance à rien. C'est un "type de données", qui définit (entre autres) les données et fonctions des instances qui sont des objets. Une classe n'est pas un objet (Il n'y a pas de classe "classe", ni de classe "objet" contrairement à d'autres langages qui intègrent l'introspection).

Classer les gens en "fanas de la sémantique" et autres "défenseurs du dogme" ne vous mène à rien, du moins quant à la compréhension de C++. Si c'est l'objectif, ce temps serait mieux utilisé à lire un texte de base sur la notion d'objet. Mais vous faites comme vous voulez.

EDIT: méfiez vous quand même, les cours qu'on trouve sur Internet contiennent des approximations qui finissent hélas par causer de fausses compréhensions. Exemples : "les classes sont la base de la programmation objet" (faux : c'est l'objet. Il y des langages, à prototype par exemple, où on n'a pas de notion de classe). "Un objet est un élément d'une classe (pas exact, il ne s'agit pas d'une relation ensembliste)"

-
Edité par michelbillaud 28 juin 2017 à 13:03:11

  • Partager sur Facebook
  • Partager sur Twitter
28 juin 2017 à 12:32:47

Parmenide a écrit:

-tout porte à croire que dans la première version il n’existe aucune certitude de pouvoir préciser la valeur de m_x par les moyens utilisés (résultats différents)

-tout donne à penser que l’obtention de la valeur de m_x réside seulement dans la seconde version. (égalité des résultats).

Non. On obtient a chaque fois la valeur de m_x, le résultat est parfaitement prédictible et correspond à ce que la norme C++ prevoit.

Parmenide a écrit:

mais oui le point serait un pointeur ?

Non.

Parmenide a écrit:

en cela elles vérifient le dogme.

Ce n'est pas un dogme (ie une affirmation que l'on ne peut pas contester), mais un choix de la norme C++.

Parmenide a écrit:

Dans le cas N°1, nonobstant le mode d’initialisation des deux attributs, comme dirait mon pote gendarme, bien que les expressions pointent sur l’attribut « m_x » à l’identique du cas N° 2, les résultats sont différents.

Ok. Tu n'as pas compris que la valeur de "m_x" contenu dans la variable "a" n'est pas la même que la valeur de "m_x" contenu dans la variable "b".

Tu as 2 données différentes en mémoire, qui peuvent avoir des valeurs différentes. C'est ce que t'a expliqué Deedolith en montrant les adresses memoires.

Parmenide a écrit:

Je vous laisse à penser ce que peut représenter une variable qui à deux adresses. Je connais les adresses à plusieurs étiquettes, mais l’étiquette à plusieurs adresses c’est encore hors de mon parcours ..

La seule explication que je me donne hormis celle avancée dans mon intervention précédente est qu’il y a création, spontanée( ?) d’une copie de « m_x », la valeur de initiale de « m_x » attribut étant en réalité demeurée la même ce que semble confirmer un premier retour d’appel de « a.foo() ».

Je pourrai concevoir que l’étiquette « m_x » second correspond à une adresse qui contient l’adresse de « m_x » premier, les deux « m_x » n’en faisant en réalité qu’un, mais dans cette éventualité les deux mêmes étiquettes seraient modifiées lors du second appel par la valeur de « m_a » , ce qui n’est pas.

Ok, la suite confirme que tu n'as pas compris que tu as affaire a 2 données différentes en mémoire.

Parmenide a écrit:

CQFD

Ok. Prémisses fausses, donc conclusion fausse.

-
Edité par gbdivers 28 juin 2017 à 12:47:32

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
29 juin 2017 à 9:38:47

Bonjour

Je crois qu’il serait temps d’envisager mettre un terme à mes échanges. Je pense que votre état de spécialisation est tel que vous êtes dans l’impossibilité de trouver le lien qui me permettrait de me forger une opinion. Vos réponses sont sans doute pertinentes mais pour qui ne baigne pas dans le langage ce n’est pas évident. Je ne sais pas si vous avez eu l’occasion de donner à quelqu’un qui approche pour la première fois un ordinateur, les éléments qui lui permettront d’utiliser ne fusse qu’un éditeur de texte, mais il y faut des dispositions particulières tant il est difficile de ne pas omettre ce qui paraît être au formateur une évidence.

Je ne voudrais pourtant pas me retirer sans une dernière tentative. Aussi je vous propose la démarche ci-après.

Règles : ne pas présumer ce que je sais ou ne sais pas du c++ , ne pas envisager de m’apporter de l’aide sur ce point, n’envisager rien d’autre que de répondre à la question posée par « Oui » ou par « Non ». Je me réserve d’en tirer de moi-même la bonne conclusion. Si vous souhaitez malgré tout commenter faites précéder votre réponse par la mention « oui » ou par la mention « non » .

Hypothèse :une classe A et une classe B.

La classe A est composée d’un seul attribut « m_x » et d’une seule méthode « foo() » dont la fonction est de faire retour de la valeur de « m_x ».

La classe B est composée d’un seul attribut, particulier, « A m_a » et d’une seule méthode « bar() » dont la seule fonction est de faire retour de la valeur de « m_x ».

En dépit des divers modes d’initialisation des deux attributs et des changements possibles par l’ajout d’autres méthodes dela valeur de «  m_x » (exclu dans l’hypothèse) , « m_x » a pour valeur par exemple « 30 » à l’instant « t ».

Résultat recherché

Pour une raison quelconque mais impérative laissée à votre imagination, un intervenant doit à l’instant « t » s’assurer de la valeur de « m_x ».

Dans l’idée de réduire pour ne pas dire éliminer, le risque d’erreur dans la valeur de retour, il utilise les deux modes d’accès, «a. foo() » et «b. bar() ». Il n’est pas en mesure, bien sûr, de modifier ou d’adapter le programme. La décision qu’il doit prendre est liée à la lecture des résultats ici « 30 » par hypothèse.

Question : Rappel la réponse ne requiert qu’un « Oui » ou qu’un « Non ».

L’intervenant est-il en mesure d’avoir la certitude d’avoir obtenu, en retour des deux appels, la valeur de « m_x » à l’instant « t » . ? ( je n’utilise pas l’expression « la valeur réelle »)

Merci.

  • Partager sur Facebook
  • Partager sur Twitter
29 juin 2017 à 9:59:30

Parmenide a écrit:

L’intervenant est-il en mesure d’avoir la certitude d’avoir obtenu, en retour des deux appels, la valeur de « m_x » à l’instant « t » . ?

Oui.

----------------------------------------------------------------------------

Ok, maintenant que j'ai répondu par oui/non a ta question (ce que j'avais déjà fait dans le message précédent), je reviens sur ton message.

Parmenide a écrit:

Je crois qu’il serait temps d’envisager mettre un terme à mes échanges. Je pense que votre état de spécialisation est tel que vous êtes dans l’impossibilité de trouver le lien qui me permettrait de me forger une opinion. Vos réponses sont sans doute pertinentes mais pour qui ne baigne pas dans le langage ce n’est pas évident. Je ne sais pas si vous avez eu l’occasion de donner à quelqu’un qui approche pour la première fois un ordinateur, les éléments qui lui permettront d’utiliser ne fusse qu’un éditeur de texte, mais il y faut des dispositions particulières tant il est difficile de ne pas omettre ce qui paraît être au formateur une évidence.

As tu envisagé que le problème vient de toi et pas de nous ?

Les réponses qui t'ont été donnée varient en longueur et en détails, mais le fond est le même.

Mon impression est que tu sembles avoir tes propres explications en tête, qui sont fausses, et tu rejettes nos explications parce qu'elles ne vont pas dans le sens de ce que tu penses.

Dans les codes que tu as montré, on t'a dit que les résultats obtenus étaient parfaitement prédictibles et correspondaient a ce que la norme C++ prevoit. Tu es le seul a penser que tes codes montrent quelque chose d'étrange.

Par contre, tu as raison sur un point : cela ne sert a rien de continuer les echanges. Tant que tu ne voudras pas remettre en question ce que tu penses et que tu acceptes d'essayer de comprendre nos explications.

-
Edité par gbdivers 29 juin 2017 à 10:11:23

  • Partager sur Facebook
  • Partager sur Twitter
29 juin 2017 à 11:05:07

On va faire l'analogie avec des boites:

Une variable, c'est une boite.
Une valeur, c'est ce qu'il y a dedans.

Si tu as 2 boites à sucre, une à droite, une à gauche, tu es bien d'accord qu'elles sont differentes (rien que leur localisation suffit à les differentier).
J'appelerai donc ces boites respectivement: Boite à sucre de droite, et Boite à sucre de gauche.

Si tu place 1 sucre dans chaque boite, tu obtiens:
- 1 sucre dans la Boite à sucre de droite.
- 1 sucre dans la Boite à sucre de gauche.

Tu peux sans problèmes, retirer 1 sucre de la Boite à sucre de gauche, ou ajouter 1 sucre dans la Boite à sucre de gauche sans que cela n'aie d'impact sur la Boite à sucre de droite. (Fais la manip chez toi, c'est exactement ce que je décrit).

Ton programme foncionne exactement de cette façon, la seul difference, est que les boites (les variables) et les sucres (les valeurs) sont dématérialisées.

  • Partager sur Facebook
  • Partager sur Twitter
29 juin 2017 à 16:00:55

il va falloir arrêter ce sujet, ça me donne trop faim.

Mais bon, à partir de ceci

<< il utilise les deux modes d’accès, «a. foo() » et «b. bar() ».>>

il semble bien que la fausse conception obstinée, c'est d'établir un lien indu entre la variable a du main, et la donnée membre m_a de la variable b.   Elles sont de même type (classe A), mais c'est le seul rapport entr'elles. Ce sont deux objets distincts.

Faites précéder votre réponse par la mention "j'ai bien compris".

-
Edité par michelbillaud 29 juin 2017 à 16:06:31

  • Partager sur Facebook
  • Partager sur Twitter
29 juin 2017 à 16:24:43

michelbillaud a écrit:

il va falloir arrêter ce sujet, ça me donne trop faim.

On a des petits gâteaux au boulot, si tu veux. Et le cafe (et le the, of course) est fournit aussi.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
30 juin 2017 à 8:20:07

Bonjour gbdivers/int21h

INT21Hj’ai pensé à un moment que tu faisais une interruption sélective. On ne sait plus sur quel registre danser.

J’ai pris enfin connaissance de ton Euréka. La première fois je l’ai trouvé un peu beaucoup abscons. Mais devant mon scepticisme toujours présent à la lecture des réponses reçues des divers intervenants, je me suis consacré à trouver une réponse par moi-même par le biais de la lecture des adresses des différents membres du programme et, de mes constatations en relation avec tes explications, a enfin failli le lien que je recherchais. Il me manquait un élément que tes explications m’ont apportées Le résultat de mes constatations s’éclaire en plus par le biais de tes explications Un grand merci.

Un seul point me pose encore interrogation c’est : pourquoi le constructeur de la donnée membre « m_x », normalement sollicité par l’objet type « A »est sollicité une seconde fois lors de la création de l’objet type « B » y compris dans le cas oùA::A(int x): m_x(x)etB::B(int z) : m_a(z)

Cette dernière formulation me parait plus en adéquation avec la raison d’être POO.

Merci gbdivers de m’avoir consacré du temps, toi et les autres, alors que semblait-il j’étais rétif à toutes les explications. S’agissant de la transmission du savoir c’est un vieux débat ici sans intérêt. Pour ta gouverne et dans ton langage quand il y a une lvalue et une rvalue et il faut en ce qui me concerne que l’opérateur se justifie.

Il n’en reste pas moins que dans le contexte du petit programme objet de la discussion les résultats affichés peuvent selon le cas être semblables ou différents l’un de l’autre.

A partir du moment qui influe sur le résultat final le déroulement est clair et logique et justifie très bien la différenciation des résultats. Pour moi ma religion est faite l’utilisation d’une instance de classe dans une autre classe est à éviter.

Merci à tous ceux qui m’ont consacré quelques instants, mais peut-être ma question méritait d’être posée et surtout d’être résolue. Elle a au moins donné lieu à échanges. Je reviendrai de temps en temps consulter le forum pour savoir si quelqu’un a posté une réponse satisfaisante concernant la raison de la seconde initialisation de « m_x ».

Mon passage laborieux n’aura pas été inutile pour moi. Mine de rien j’ai fait moisson de nombreux éléments. Parler avec soi-même n’a pas toujours que des avantages.

Merci,merci.encore aux intervenants.

En tout pays, il y a une lieue de mauvais chemin

  • Partager sur Facebook
  • Partager sur Twitter