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

 C++ Discussion :

Déclaration d'une class ayant été définie dans une autre class.


Sujet :

C++

  1. #1
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Points : 239
    Points
    239
    Par défaut Déclaration d'une class ayant été définie dans une autre class.
    Bonjours à tous,

    J'aurais besoin de faire une déclaration d'une classe elle même définie dans une autre class.

    Pour exemple, voici les définitions de mes deux classes :
    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 A
    {
    public:
    	int a;
     
    	class B
    	{
    		int b;
    		[...]
    	};
     
    	[...]
    };
    Et maintenant j'aimerai pouvoir faire la déclaration de la class A::B dans un autre fichier d'entête ne pouvant pas inclure celui ayant ces défintions : comment fait-on à ce moment là ?

    Merci de votre lecture ainsi que de vos réponses.

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Salut,

    De manière générale, si tu envisages de définir une classe imbriquée (B est imbriquée dans A ), c'est parce que:
    1. tu estimes que A a besoin de B pour son comportement interne
    2. tu estimes que tu n'auras jamais besoin de la classe imbriquée si tu ne connais pas la classe dans laquelle elle l'est
    De toutes évidences, la deuxième condition n'est pas remplie ici

    Dés lors, il y a deux solutions:
    1. Soit, tu ne dois pas imbriquer B dans A
    2. Soit, tu ne dois pas utiliser A::B sans pouvoir inclure le fichier d'en-tête de A
    Tu n'en dis malheureusement pas assez pour qu'il nous (non, ce n'est pas le nous majestatif, d'autres que moi peuvent essayer de répondre ) soit possible de déterminer dans quelle situation tu te trouves

    Ceci dit, les pistes que tu peux explorer sont:
    • sortir purement et simplement B de A
    • Placer B dans un espace de noms séparés
    • A est peut etre un espace de noms et non une classe
    • Tu n'as besoin de B::A que dans le fichier d'implémentation (dans lequel tu peux donc inclure le fichier d'en-tête de A)

  3. #3
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Points : 239
    Points
    239
    Par défaut
    Bonjours,

    Et bien en faite je suis en train de recoder mon système d'Octree. Le précédent etait implémenté de la manière suivante :

    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    namespace Abstract
    {
    	class Element3D;
    }
     
    namespace Octree
    {
    	class Node
    	{
    		Node * apChildren[ 8 ];
    		Abstract::Element3D ** apElements;
    		[...]
    	};
     
    	class Instance
    	{
    		Node * pMainNode;
    		[...]
    	};
    }
     
    namespace Abstract
    {
    	class Element3D
    	{
    		Octree::Node * pParentNode;
    		[...]
    	};
    }
    Mais ce qui me déplai, c'est d'instancier un octree par Octree::Instance monOctree;

    De plus les Octree::Node ne sont utilisé que par Octree::Instance et Abstract::Element3D, donc je voulais definir Octree::Node en temps que privé dans une class Octree (à la place du namespace) avec une déclaration d'amitié pour la class Abstract::Element3D, encapsulant ainsi d'avantage mes données.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Peut être as tu "simplement" un problème pour déterminer la responsabilité de ta classe octree et node...

    Faisons simple: pour toi, à quoi correspond un octree, et à quoi correspond un node

    De prime abord, je dirais que octree correspond à une "collection" de node, et que node correspond au type d'éléments (récursif) conenue par le octree.

    L'idée est donc de pouvoir écrire un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
        Octree tree(/* ... */);
        remplireOctree(tree);
        manipulerOctree(tree);
        return 0;
    }
    où des fonctions comme remplireOctree et manipulerOctree manipulent (peut etre) un octree et un (ou des) nodes.

    Nous pourrions donc partir sur quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Octree
    {
    public:
        struct Node
        {
            int value;
            Node * children[8];
        }
        /* les fonctions qui vont bien pour manipuler un octree */
    private:
        Node root;
    }
    Mais, si l'on prend exemple sur les collections fournie par la STL, on se rend compte qu'il est préférable d'éviter de fournir directement accès au détail d'implémentation que la structure Node représente.

    L'idée de base est de fournir une structure qui permette de parcourir l'arbre dans un ordre donné, en veillant, le cas échéant à faire en sorte de respecter la const-correctness.

    Cette structure particulière est, généralement, appelée iterateur, et est généralement fournie dans une version constante ("lecture seule") et dans une version non constante ("lecture / écriture").

    Notre Octree pourrait donc ressembler à quelque chose comme
    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    class Octree
    {
        struct Node
        {
            int value;
            Node * children[8];
        };
        public:
        class Iterator
        {
            friend class Octree;
            public:
                /* permet d'accéder à la valeur grace à l'opérateur * */
                int & operator *(){return node->value;}
                /* permet d'accéder à la valeur grace à l'opérateur -> */
                int & operator ->(){return node->value;}
                /* soyons imaginatif : permet d'accéder à au noeud enfant
                 * correspondant à l'index fourni
                 */
                Iterator operator[](size_t index)
                {
                    return iterator(data_->children[index];
                }
                Iterator ++()
                {
                     /* voir ce que l'on considère comme implémentation */
                }
            private:
                Iterator(Node * data):data_(data){}
                Node *data_;
        };
        class ConstItertor
        {
             /* sensiblement pareil que Iterator, mais en veillant à renvoyer
              * une référence constante pour * et ->
              */
        }
        /* au minimum, les fonctions */
        Iterator begin(){return Iterator(&root);}
        Iterator end(){return Iterator(NULL);}
        ConstIterator() const{return ConstIterator(&root);}
        ConstIterator() const{return ConstIterator(NULL);}
        /* sans doute d'autres fonctions, d'insertion, de suppression,
         * ...
         */
    private:
        Node root;
    };
    Après, bien sur, il y a tout le problème de la gestion dynamique de la mémoire, mais c'est un autre problème

    Le fait est que, en travaillant de la sorte, la seule "vue" que tu aies sur ton octree est... la classe Octree, et que le seul moyen d'accéder (ou peut s'en faut) aux données qu'il contient est... de passer par les classes Iterator et ConstIterator.

    Ces dernières ne serviront, quoi que tu fasses, qu'à te permettre d'accéder aux différents éléments de ton Octree, et tu n'en auras donc besoin que... lorsque tu auras, effectivement, besoin d'accéder aux membres d'une instance d'octree et donc ... lorsque tu en auras inclus le fichier d'en-tête

    NOTA: le code n'a absolument pas été testé et correspond à une implémentation naïve des idées d'octree, de node et d'itérateurs... C'est très certainement susceptible d'être amélioré

  5. #5
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Points : 239
    Points
    239
    Par défaut
    Bonsoir,

    Merci beaucoup !

    Mais j'ai bien peur de ne pas avoir été très clair sur mon probleme. L'objectif d'un Octree est de stocker un ensemble d'objet 3D sous la forme d'une méga structure accélératrice à la manière d'un arbre binaire (mais en 3D ), entre plusieurs type d'objet fils d'une class abstraite (Abstract::Element3D ici). Donc la class Node ici n'est que pour la structure interne lié au fonctionnement élémentaire de l'octree. Il a pour avantage de pouvoir de donner de manière très optimisée l'ensemble des objets dans le champ de vision de la camera. Alors un itérateur pour celui ci ne serait que contre productif. Comme si on voulait faire une recherche avec un itérator sur une std::map.


    L'objectif est donc de donner un coup de jeunesse à mon ancien Octree. Et celui ci doit rester très performant. Donc c'est beaucoup d'amitié qui sont définies entre plusieurs classes ne pouvant fonctionner qu'ensemble dans un but d'optimisation. Or pour améliorer l'encapsulation des données, je voulais simplement cacher ma class Node dans le private de la class Octree pour éviter que les classes n'intervenant pas directement avec l'Octree ne puisse pas même la voir. Le souci est que la class Node à des amitiés avec d'autre classes ne pouvant pas inclure sont .h. D'où ma question.

    EDIT : j'ai trouvé comment détourné le problème. Merci beaucoup de tes initiative koala01 !

  6. #6
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 196
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 196
    Points : 17 165
    Points
    17 165
    Par défaut
    Bonjour!
    Citation Envoyé par LastSpear Voir le message
    EDIT : j'ai trouvé comment détourné le problème.
    Et comment, s'il te plait?

  7. #7
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Points : 239
    Points
    239
    Par défaut
    Oups oui pardon, j'ai oublié de dire comment

    En faite, c'est tout con : comme Node est maintenant dans le private de Octree, alors plus besoin de mettre ces propres éléments en privé, donc Node n'est plus une class mais une struct, donc les class devant avoir une amitié avec on Node peuvent simplement y avoir accès avec l'amitié de Octree. Or si un element à une amitié avec Octree, alors celui ci va intéragir avec ses Nodes forcément. Donc il y a équivalence sur les deux amitiés, et encapsulation bien propre.

  8. #8
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 196
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 196
    Points : 17 165
    Points
    17 165
    Par défaut
    Merci bien!

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

Discussions similaires

  1. Appeler dans une requête des variables définies dans une macro
    Par piflechien73 dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 20/08/2009, 16h12
  2. Réponses: 40
    Dernier message: 21/06/2007, 18h58
  3. [MySQL] récupérer dans une boucle chaque information MySQL dans une variable différente
    Par gtenthorey dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 06/05/2007, 23h34
  4. Déclarer une fonction ayant 2 prototypes dans une DLL
    Par Jayceblaster dans le forum Delphi
    Réponses: 8
    Dernier message: 17/02/2007, 13h00
  5. Réponses: 2
    Dernier message: 20/06/2006, 09h22

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