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 :

Typedef et inclusion cyclique


Sujet :

Langage C++

  1. #1
    Membre actif

    Homme Profil pro
    Développeur Windev
    Inscrit en
    Mai 2006
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Drôme (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Windev

    Informations forums :
    Inscription : Mai 2006
    Messages : 34
    Points : 223
    Points
    223
    Billets dans le blog
    1
    Par défaut Typedef et inclusion cyclique
    Bonjour à tous.

    Je développe actuellement un projet basé sur QT.
    J'utilise le pointeur intelligent QExplicitlySharedDataPointer.

    Afin d'améliorer la lisibilité, je souhaite définir un type pour chacun de mes objets avec typedef.
    Plutôt que d'utiliser QExplicitlySharedDataPointer<Objet>, je préfèrerai utiliser Objet::pointor.

    Jusqu'à présent, ça marchait, sauf au moment où j'ai deux entêtes qui s'appellent mutuellement et qui définissent tous les deux un "pointor".

    Voici mes deux classes, chacune définis dans un fichier à part :

    Le fichier note.h
    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
    #ifndef NOTE_H
    #define NOTE_H
     
    #include "tablenote.h"
     
     
    class Note
    {
    public:
        typedef QExplicitlySharedDataPointer<Note> Pointor;
     
    private TableNote::pointor table;
     
    }
    #endif
    et voici mon fichier tablenote.h

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #ifndef TABLENOTE_H
    #define TABLENOTE_H
     
    #include "Table.h"
     
    class TableNote
    {
    public:
    typedef QExplicitlySharedDataPointer<TableNote> pointor;
     
    Note::pointor createNote();
    }
    #endif
    J'ai bien compris le problème, l'un de mes "pointor" n'est pas encore défini quand je défini l'entête.
    Mais que faire pour avoir une écriture facile à lire ?

    Je pourrais bien sûr définir dans un fichier à part des TableNotePointor et NotePointor mais je préfère l'ecriture TableNote::pointor et Note::pointor.

    auriez-vous des conseils / astuces à me donner ?

    Merci d'avance à tous ceux qui prendront la peine de lire mon message et un plus grand merci à ceux qui essaieront d'y répondre.

    Bonne journée à tous !
    Mes publications : mise en place en cours
    Mon blog sur WinDev: http://blog.ytreza.org

  2. #2
    Expert éminent sénior

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 031
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 031
    Points : 11 476
    Points
    11 476
    Billets dans le blog
    11
    Par défaut
    Je ne sais pas si c'est possible en gardant ta notation Note :: Pointor et TableNote :: Pointor
    Pour résoudre le même genre de problèmes, je crée généralement un fichier .h (typedefs.h) dans lequel je mets les déclarations de classes et que j'inclue dans tous mes headers.
    Pour ton cas, ça donnerait ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class Note;
    class TableNote;
     
    typedef QExplicitlySharedDataPointer<Note> NotePtr;
    typedef QExplicitlySharedDataPointer<TableNote> TableNotePtr;
    Mais comme je le disais auparavant, tu perds la notation Note :: Pointor
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  3. #3
    Membre actif

    Homme Profil pro
    Développeur Windev
    Inscrit en
    Mai 2006
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Drôme (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Windev

    Informations forums :
    Inscription : Mai 2006
    Messages : 34
    Points : 223
    Points
    223
    Billets dans le blog
    1
    Par défaut
    Oui, effectivement, c'est une solution.
    Je pense que je vais partir sur ce principe, même s'il ne correspond pas tout à fait à ce que je souhaite.

    Mais bon, ce n'est peut-être pas possible.

    Je vais attendre un peu avant de mettre résolu, peut être qu'une autre idée sera là.

    En tout cas, merci à toi.
    Ca fait plaisir d'avoir une réponse rapide.
    Mes publications : mise en place en cours
    Mon blog sur WinDev: http://blog.ytreza.org

  4. #4
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Je ne te garantit rien, mais je pense que si tu spécifie que Note::pointor est un typename et que tu fait une déclaration anticipée de Note, sa devrait marcher. Je ne te garantit rien, d'autant plus que ce n'est pas un Note::pointor*.

  5. #5
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Bonsoir

    Je voulais réagir sur un point en particulier : j'ai l'impression que tu n'utilise pas correctement la classe QExplicitlySharedDataPointer.

    Cette classe permet d'implémenter facilement le COW (copy en write, lire la documentation à ce sujet). Pour rappel, le COW permet d'éviter la copie des données contenus dans un objet lors de la copie de cet objet. La copie des données n'est effectué que lors d'un accès en écriture. QExplicitlySharedDataPointer (et son équivalent "implicite", QSharedDataPointer) s'utilise avec QSharedData.

    Par exemple, pour implémenter le COW dans ta classe Note, il faudrait écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class NoteData : public QSharedData
    {
        // les données contenu auparavant dans ta classe Note
    };
     
    class Note
    {
    private:
        QSharedDataPointeur< NoteData > data;
        // ta classe ne contient aucune autre variable membre
     
    public:
        // tu utilises ta classe en accédant à tes données avec "data->" 
    }

    Pour en revenir au code que tu donnes :

    - ta classe Note n'est pas une implémentation du COW pour ta classe NoteTable et ta classe NoteTable n'est pas une implémentation du COW pour ta classe Note. Tu ne dois donc pas utiliser QExplicitlySharedDataPointer dans ton cas.

    - Qt fournit d'autres pointeurs intelligents. Tu devrais lire le tutoriel sur les pointeurs de Qt.

    - Tes objets Note sont créé (à priori) dans ta classe TableNote : il peut être intéressant dans ce cas d'utiliser un pointeur intelligent. Par contre, ton pointeur vers TableNote dans Note est juste (à priori) un moyen de conserver le parent. Il n'y a pas besoin d'utiliser un pointeur intelligent dans ce cas à mon avis : un objet TableNote est créé dans une autre classe ; si tous les pointeurs vers TableNote sont détruits dans la classe parent, ton objet TableNote n'a plus de raison d'exister. Si tu utilises un pointeur intelligent dans Note vers TableNote, ton compteur de référence ne sera pas nul et tes objets ne seront pas détruit. Tu auras une fuite mémoire.

    - Ta classe TableNote renvoi un objet Note, ce qui me semble contraire au principe de ségrégation des interfaces (voir le blog d'Emmanuel Deloget pour les explications) : ta classe qui crée un objet TableNote doit également connaitre l'interface de ta classe Note. C'est à ta classe Note de gérer chaque Note (note de musique ou note d'un examen ?)

    - Avec le même principe, ta classe Note ne devrait probablement pas avoir besoin d'un pointeur vers TableNote (surtout si tu respectes le principe de responsabilité unique).

    - A priori, ta classe TableNote est un conteneur d'objets Note avec composition : TableNote contient plusieurs objets Note, chaque objet Note possède un seul parent TableNote et si tu détruit TableNote, tu dois détruire tous ses objets Note. A mon avis, ta classe TableNote devrait simplement contenir un conteneur de Note (par exemple un QList<Note>).

    - A priori, tu n'utilises pas le polymorphisme d'héritage donc tu n'as pas besoin d'utiliser de pointeurs. En bref, en paraphrasant un message récent de Joel F : le plus simple pour utiliser correctement des pointeurs est de ne pas en utiliser )


    Au final, ton implémentation peut ressembler à ça :
    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 Note
    {
        // utilisation de ta classe
     
        // en plus, uniquement si c'est nécessaire :
    private:
        TableNote* parent;
    };
     
    class TableNote
    {
    public:
        void createNote(); // aucun paramètre ? c'est étonnant
     
    private:
        QList<Note> notes;
    };
    Si tu donnes plus de détail sur ta conception et ce que tu veux faire, on pourra t'aider à améliorer ton design et l'utilisation des pointeurs.


    PS : il existe un forum spécifique pour Qt pour les questions spécifiques, en particulier les pointeurs intelligent de Qt. Je n'ai pas déplacer ton message dans ce forum puisque ta question initiale concernait un problème général C++ (même si il y avait des précisions à apporter côté Qt)

  6. #6
    Membre actif

    Homme Profil pro
    Développeur Windev
    Inscrit en
    Mai 2006
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Drôme (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Windev

    Informations forums :
    Inscription : Mai 2006
    Messages : 34
    Points : 223
    Points
    223
    Billets dans le blog
    1
    Par défaut
    Tout d'abord, merci pour vos réponses.

    @NoIdea :
    Je pense avoir testé ta méthode mais ça n'a pas fonctionné. Ensuite, je m'y suis peut-être mal pris. Mais il semble qu'il n'aime pas car quand je déclare Note par anticipation, je ne peux pas indiquer qu'il dérive de QSharedData.



    @gbdivers :
    Un début de solution qui me fait penser que j'ai un mauvais design. Je vais continuer le débat malgrè qu'on ne soit pas sur le forum QT. (J'aurais presque envie de déplacer le sujet ).

    Tout d'abord, c'est pour un logiciel de prise de note. Donc, une note correspond à un texte.

    - A priori, tu n'utilises pas le polymorphisme d'héritage donc tu n'as pas besoin d'utiliser de pointeurs. En bref, en paraphrasant un message récent de Joel F : le plus simple pour utiliser correctement des pointeurs est de ne pas en utiliser )
    Alors, j'utilise le polymorphisme. Ici, j'ai fait un exemple simplifié pour présenter mon problème et l'utilisation de pointeur m'était donc obligatoire.


    - ta classe Note n'est pas une implémentation du COW pour ta classe NoteTable et ta classe NoteTable n'est pas une implémentation du COW pour ta classe Note. Tu ne dois donc pas utiliser QExplicitlySharedDataPointer dans ton cas.

    - Qt fournit d'autres pointeurs intelligents. Tu devrais lire le tutoriel sur les pointeurs de Qt.
    Ensuite, pour le COW, je n'ai pas forcément compris de quoi il en retourne et je vais me pencher un peu plus sur la question, mais l'idée globale que je souhaite, c'est que mon objet note ne soit pas dupliqué lorsque je le modifie. Je me suis basé sur le tutorial que tu cites pour faire ce choix. Je me replongerai dedans mais il me semblait que ce pointeur correspondait à ce que je souhaitais.

    - A priori, ta classe TableNote est un conteneur d'objets Note avec composition : TableNote contient plusieurs objets Note, chaque objet Note possède un seul parent TableNote et si tu détruit TableNote, tu dois détruire tous ses objets Note. A mon avis, ta classe TableNote devrait simplement contenir un conteneur de Note (par exemple un QList<Note>).
    Mes objets notes sont effectivement créés par la TableNote mais ce n'est pas un conteneur. Les notes sont stockées dans une base de données. J'effectue seulement une lecture de cette base, je créé une note et je la lâche dans la nature (d'où l'utilisation d'un pointeur intelligent).

    - Tes objets Note sont créé (à priori) dans ta classe TableNote : il peut être intéressant dans ce cas d'utiliser un pointeur intelligent. Par contre, ton pointeur vers TableNote dans Note est juste (à priori) un moyen de conserver le parent. Il n'y a pas besoin d'utiliser un pointeur intelligent dans ce cas à mon avis : un objet TableNote est créé dans une autre classe ; si tous les pointeurs vers TableNote sont détruits dans la classe parent, ton objet TableNote n'a plus de raison d'exister. Si tu utilises un pointeur intelligent dans Note vers TableNote, ton compteur de référence ne sera pas nul et tes objets ne seront pas détruit. Tu auras une fuite mémoire.
    Ca, c'est une remarque très judicieuse. Effectivement, je devrais passer par un pointeur *. Et ça, ça me permettra de supprimer la référence cyclique sur TableNote:ointor. J'ai encore pas mal de progrès à faire au niveau de la conception.


    Bon, en gros, tu m'a donné une excellente vision des choses, un lien qui me semble très utile (le blog d'Emmanuel Deloget). Je vais revoir mon code et lire plus en détail tout ce que tu m'as donné / expliqué.

    Merci beaucoup !!!
    Mes publications : mise en place en cours
    Mon blog sur WinDev: http://blog.ytreza.org

  7. #7
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Alors, j'utilise le polymorphisme. Ici, j'ai fait un exemple simplifié pour présenter mon problème et l'utilisation de pointeur m'était donc obligatoire.
    Je faisais la remarque simplement parce que c'est une erreur qui revient souvent d'utiliser un pointeur sans que cela soit nécessaire (particulièrement pour les développeurs venant de java).

    Ensuite, pour le COW, je n'ai pas forcément compris de quoi il en retourne et je vais me pencher un peu plus sur la question, mais l'idée globale que je souhaite, c'est que mon objet note ne soit pas dupliqué lorsque je le modifie. Je me suis basé sur le tutorial que tu cites pour faire ce choix. Je me replongerai dedans mais il me semblait que ce pointeur correspondait à ce que je souhaitais.
    L'idée derrière le COW est que lorsque l'on duplique un objet sans le modifier, les données en mémoire sont les mêmes entre les 2 objets. Donc on peut manipuler indépendamment les 2 objets et utiliser qu'une seule version des données en mémoire.
    La copie des données en mémoire n'intervient que lorsque l'un des 2 objets est modifié : les données en mémoire ne sont plus les même dans ce cas.

    Dans ton cas, tu ne souhaites pas implémenter le COW. Donc QExplicitlySharedDataPointer n'est pas adapté dans ton cas (plus précisément, même s'il réalise ce que tu souhaites, il n'a pas été conçu pour ce type d'utilisation et tu ne respecterais pas le "contrat" si tu l'utilisais pour une autre utilisation que ce qu'il a été conçu)

    Tu devrais utiliser un QSharedPointer je pense.

    Mes objets notes sont effectivement créés par la TableNote mais ce n'est pas un conteneur. Les notes sont stockées dans une base de données. J'effectue seulement une lecture de cette base, je créé une note et je la lâche dans la nature (d'où l'utilisation d'un pointeur intelligent).
    Le nom m'a induit en erreur... ce qui veut probablement dire que le nom est mal choisit
    A priori, sa fonction est de créer des objets Note. Donc à mon avis, tu devrais te tourner vers le design pattern Factory et renommer ta classe (par exemple "NoteFactory") :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class NoteFactory
    {
    public:
        QSharedPointer<Note> createNote();
    };
    Par contre, je suis étonné que tu n'as pas de paramètre pour ta création d'objet Note. Comme tu as dit que tu utilisais le polymorphisme d'héritage, je suppose que tu as du simplifier la déclaration de ta fonction pour l'exemple, non ?

    PS : c'est Qt (ça se prononce "cute") et non QT (ie quicktime)

  8. #8
    Membre actif

    Homme Profil pro
    Développeur Windev
    Inscrit en
    Mai 2006
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Drôme (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Windev

    Informations forums :
    Inscription : Mai 2006
    Messages : 34
    Points : 223
    Points
    223
    Billets dans le blog
    1
    Par défaut
    C'est un plaisir de discuter avec toi

    D'accord pour le QSharedPointer, je vais regarder plus en détail.


    Le nom m'a induit en erreur... ce qui veut probablement dire que le nom est mal choisit
    A priori, sa fonction est de créer des objets Note. Donc à mon avis, tu devrais te tourner vers le design pattern Factory et renommer ta classe (par exemple "NoteFactory") :
    Tout simplement que je ne respectais pas la notion de responsabilité unique. Mais je vais y accorder plus d'attention. Et puis, en le nommant Table, j'ai songé aux tables SQL.


    Par contre, je suis étonné que tu n'as pas de paramètre pour ta création d'objet Note. Comme tu as dit que tu utilisais le polymorphisme d'héritage, je suppose que tu as du simplifier la déclaration de ta fonction pour l'exemple, non ?
    Oui, je n'avais pas envie d'embêter tout le monde avec des détails.



    PS : c'est Qt (ça se prononce "cute") et non QT (ie quicktime)
    Je me demandais aussi pourquoi Quicktime n'avait pas encore attaqué Nokia / trolltech pour vol de nom.
    Mes publications : mise en place en cours
    Mon blog sur WinDev: http://blog.ytreza.org

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. d'inclusion cyclique et makefile
    Par vincent.mbg dans le forum C
    Réponses: 4
    Dernier message: 14/06/2010, 18h05
  2. probleme inclusion cyclique avec namespace
    Par befalimpertinent dans le forum C++
    Réponses: 4
    Dernier message: 27/05/2010, 09h52
  3. inclusion cyclique et compilation
    Par qertbu65 dans le forum C++
    Réponses: 10
    Dernier message: 11/05/2010, 15h36
  4. problème inclusion cyclique
    Par marion5515 dans le forum Débuter
    Réponses: 7
    Dernier message: 20/05/2009, 13h53
  5. Inclusion cyclique: mauvaise analyse?
    Par zabibof dans le forum C++
    Réponses: 4
    Dernier message: 12/09/2007, 16h36

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