IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Récupérer un pointeur sur une classe à sa création


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 122
    Par défaut Récupérer un pointeur sur une classe à sa création
    Bonsoir à toutes et à tous,

    Suite au fil "Accès indirect aux éléments d'une classe" je souhaite récupérer un pointeur sur une classe à sa création.

    L'idée est d'utiliser "this".

    J'ai trouvé une première manière, mais qui ne me satisfait pas, car je récupère le pointeur justa après la création en appelant un fonction. Cette manière montre que, a priori, on peut utiliser "this". Voici ce que je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class Truc {
    public:
      int xx;
      Truc *getPtr() {
      return this;
      }
    };
     
    Truc *ptrs[10]; // Tableau de pointeur
     
    void setup() {
     
      ptrs[3] = truc.getPtr();
     
      truc.xx = 421;
      int b = (*ptrs[3]).xx; // Cela me fournit bien la valeur 421
    }
    Maintenant, je voudrais utiliser ce 'this" à la création du composant, j'écris :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class Truc {
    class Truc {
    public:
      int xx;
      Truc(Truc *myPtr) { // passage de l'adresse du paramètre
        myPtr = this; // // je voudrais que le contenu du paramètre soit égal à "this" c'est-à-dire l'adresse de "truc"
      }
    };
     
    Truc *ptrs[10]; // tableau de pointeur de type "Truc"
     
    void setup() {
     
      Truc truc(ptrs[0]); // instanciation de Truc avec le premier élément du tableau en paramètre pour récupérer le pointeur "this"
     
      truc.xx = 421;
      int b = (*ptrs[0]).xx; // je récupère une valeur, mais ce n'est pas 421 !
    }
    J'ai essayé diverses façons d'écrire cela, mais, soit ça plante à la compilation, soit ça plante à l'exécution, soit encore je n’obtiens pas la bonne valeur.

    Est-ce la syntaxe qui n'est pas bonne ?

    Est-ce que la valeur de this n'est pas encore déterminée au moment où je la demande ?

    Merci de votre aide.

    Pierre

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Dans ton code, tu passes le pointeur par copie. Donc toutes les modifications que tu lui appliques à l'intérieur de la fonction ne sont pas visibles à l'extérieur.
    Si tu faisais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      Truc(Truc *&myPtr) { // passage de l'adresse du paramètre
        myPtr = this; // // je voudrais que le contenu du paramètre soit égal à "this" c'est-à-dire l'adresse de "truc"
      }
    ça devrait aller mieux.

    Maintenant, de là à dire que le code est beau... Il faudrait en savoir plus ce que tu veux faire à la base.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #3
    Membre émérite
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 122
    Par défaut
    Merci JolyLoic,

    Modifiant mon code selon ta proposition, cela fonctionne.

    Mais, étant un débutant en C++, je m'y perd entre les "*" et les "&".

    Tu dis : "Dans ton code, tu passes le pointeur par copie". Peux-tu m'expliquer pourquoi ?

    Tu écris : Truc(Truc *&myPtr) . Peux-tu me dire comment je dois lire *&myPtr

    Ce que je veux faire : Je développe sur Arduino : un jeu de cartes basé sur un µP et muni d'un module d'affichage avec la fonction écran tactile. Je voudrais faire un mini, que dis-je, un micro OS. Je m'explique : je crée des composants visuels (boutons, afficheurs, ...) et je voudrais que lorsque qu'on appuie dessus cela déclenche un évènement mais sans que j'ai à écrire, pour chaque composant, une fonction de test pour voir si l'appui le concerne.

    D'où l'idée d'inscrire dans un tableau, de manière automatique, chaque composant à sa création (l'indice du tableau étant automatiquement incrémenté à chaque création) et ensuite, grâce à une boucle infinie, parcourir le tableau pour vérifier si tel ou tel composant a reçu un appui. Ensuite, attacher une fonction à un composant si besoin est.

    NOTA 1 : il y a très longtemps, j'avais fais un tel OS sous DOS en turbo-pascal pour un logiciel de simulation d'automatisme. Un pré-windows en sorte avec menus déroulants et tutti quanti .

    NOTA 2 : la syntaxe du C m'a toujours effrayé .

    Cordialement.

    Pierre

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Ou bien, tu vas chercher beaucoup trop loin, ou bien, tu devrais envisager des solutions toutes autres.

    Il n'y a en effet aucune raison de demander à l'objet lui-même de renvoyer un pointeur sur lui-même, étant donné qu'il est toujours possible... d'en prendre l'adresse.

    Pour autant que truc soit une variable globale (ce que je te déconseille cependant) un code aussi simple que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class Truc {
    public:
      int xx;
      /* pas besoin de ca
      Truc *getPtr() {
      return this;
      }
      */
    };
     
    Truc *ptrs[10]; // Tableau de pointeur
     
    void setup() {
     
      ptrs[3] = &truc;
     
      truc.xx = 421;
      int b = (*ptrs[3]).xx; // Cela me fournit bien la valeur 421
    }
    fera parfaitement l'affaire

    Autrement, tu peux envisager l'allocation dynamique de la mémoire, soit sous la forme de ptrs[x]= new Truc; soit en envisageant, par exemple, la mise au point d'un système proche de la fabrique( essentiellement utile si la classe Truc est susceptible de servir de classe de base dans une hiérarchie de classes).

    Il faudra, cependant, penser à libérer correctement chaque objet créé de la sorte avec un delete correspondant, ou peut être (c'est plus sécurisant ) envisager l'utilisation de pointeurs intelligents, comme les std::unique_ptr ou les std::shared_ptr (si tu dispose de C++11)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre émérite
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 122
    Par défaut
    @ koala01 : dans le code que tu me proposes, je pense que tu as oublié d'instancier truc. le code devient alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Truc truc;
    ptrs[3] = &truc;
    C'est ce que je voudrais éviter : avoir plusieurs lignes nécessaires à la création/enregistrement des composants créés.

    Voire même éviter d'avoir à fournir le paramètre ptrs dans l'instanciation, faire en sorte que cela se fasse dans une méthode du composant, mais alors, myPtr étant de type Truc, il est nécessaire de le déclarer avant la classe et donc il me faut une déclaration forward de Truc (ce que je ne sais pas encore faire, mais ça va venir ), par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    int indexComp = 0;
     
    // Déclaration forward de Truc à faire
    Truc *ptrs[10]; // tableau de pointeur de type "Truc"
     
    class Truc {
    public:
      int xx;
      Truc() {
        myPtr[indexComp] = this;
        indexComp++;
      }
    };
     
    // Déclaration de composants :
     
    Truc truc;
    Truc machin;
    ...
    Tu écris "soit en envisageant, par exemple, la mise au point d'un système proche de la fabrique( essentiellement utile si la classe Truc est susceptible de servir de classe de base dans une hiérarchie de classes)."

    Truc étant très certainement le parent de tous mes composants, il va falloir que je me penche sur ce qu'est un "système de fabrique".

    NOTA : avec Arduino, je n'ai pas d'accès à tout ce qui est std::

    Cordialement.

    Pierre

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par ChPr Voir le message
    @ koala01 : dans le code que tu me proposes, je pense que tu as oublié d'instancier truc. le code devient alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Truc truc;
    ptrs[3] = &truc;
    Je penses plutôt que tu as "zappé" la phrase qui précédait le code en quetion, que je cite ici:
    Pour autant que truc soit une variable globale (ce que je te déconseille cependant) u
    C'est ce que je voudrais éviter : avoir plusieurs lignes nécessaires à la création/enregistrement des composants créés.
    a priori, ta solution passe donc par l'allocation dynamique de la mémoire
    Voire même éviter d'avoir à fournir le paramètre ptrs dans l'instanciation, faire en sorte que cela se fasse dans une méthode du composant,
    Mais la question est alors : pourquoi voudrais tu que cela passe par une fonction membre de l'objet

    Cela donnerait à l'objet une responsabilité qu'il n'a absolument pas à avoir

    Tu écris "soit en envisageant, par exemple, la mise au point d'un système proche de la fabrique( essentiellement utile si la classe Truc est susceptible de servir de classe de base dans une hiérarchie de classes)."

    Truc étant très certainement le parent de tous mes composants, il va falloir que je me penche sur ce qu'est un "système de fabrique".
    L'idée est de faire en sorte que tu n'aies pas à connaître le type réel d'un objet afin de pouvoir l'utiliser.

    Quand on y réfléchit, siTruc sert des base à une hiérarchie de classe, chaque objet sait pertinemment quel est son type réel, ce qui fait que le seul moment où tu as besoin "qu'autre chose" connaisse le type réel d'un objet est... le moment de sa création.

    Le patron de conception "fabrique" (desing pattern Factory, en anglais) consiste à déléguer la création des différents objets réel à quelque chose qui ne fera que cela (la fabrique proprement dite) et qui renverra d'office l'objet (créé à coup de new) sous la forme d'un pointeur vers un objet de la classe de base.

    De cette manière, tu n'as même plus à t'inquiéter des différents types dérivés de ta classe de base : tout ce que tu dois connaitre, c'est la classe de base elle-même et son interface publique

    Enfin, je prend un raccourci honteux à ce niveau, car, il arrive que le polymorphisme ne suffise simplement pas et qu'il soit malgré tout nécessaire de pouvoir connaître le type réel d'un objet dans certaines circonstances bien particulières.

    Dans ce cas, on peut alors envisager le recours au double dispatch, dont l'une des mise en oeuvre est le très connu patron de conception visiteur (desing pattern visitor en anglais )
    NOTA : avec Arduino, je n'ai pas d'accès à tout ce qui est std::

    Cordialement.

    Pierre
    C'est bien dommage

    Et c'est une raison de plus pour envisager l'allocation dynamique de la mémoire, mais il est préférable de s'y prendre correctement.

    Tu devrais peut être envisager d'encapsuler ton tableau d'éléments (à moins que tu sois sur de n'avoir jamais besoin de plus de 10 objets) dans une classe dont la seule responsabilité sera de gérer la mémoire allouée dynamiquement à ce tableau (j'ai régulièrement parlé de la forme canonique de Coplien dans mes interventions, avec exemples et explications, une petite recherche sur le forum devrait te donner des pistes intéressantes ) et faire en sorte que ce soit cette classe qui s'occupe de libérer correctement la mémoire allouée aux différentes pointeurs

    Ceci dit, Truc prend alors ce que l'on appelle une sémantique d'entité, ce qui en ferait une classe non copiable et non assignable (de même que pour les classes dérivées de Truc) ce qui implique que la classe qui gérerait ton tableau de pointeurs aurait largement intérêt à ne pas pouvoir être copiée ni assignée non plus
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Récupérer un pointeur sur une classe Singleton
    Par slake13 dans le forum Débuter
    Réponses: 7
    Dernier message: 18/11/2008, 17h01
  2. Réponses: 8
    Dernier message: 30/05/2006, 01h26
  3. [C++] pointeur sur une classe
    Par PH69 dans le forum Débuter
    Réponses: 1
    Dernier message: 21/11/2005, 22h08
  4. Réponses: 14
    Dernier message: 14/03/2005, 09h16
  5. [MFC] Problème pointeur sur une classe
    Par mick74 dans le forum MFC
    Réponses: 7
    Dernier message: 14/04/2004, 14h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo