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 :

Problème de forward declaration


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 70
    Points : 50
    Points
    50
    Par défaut Problème de forward declaration
    Bonjour,

    J'ai besoin de faire un lien entre deux objets différents. C'est-à-dire qu'en partant d'un j'aimerais pouvoir atteindre l'autre et vice versa.
    Il y a quand même une hiérarchie. Voila comment je m'y suis pris :

    Child.hpp
    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 Parent; // Forward declaration (enfin j'imagine)
     
    class Child
    {
    	private:
     
    		Parent * m_myParent;
     
    	public:
     
    		Child (void);
    		~Child (void);
     
    		setParent (Parent * myParent); /* Cette méthode ne devrait pas être appelée de manière publique (d'ailleurs ca m'ennuie un peu cette construction) */
    		Parent * getParent (void);
    }
    Parent.hpp
    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
     
    #include "Child.hpp"
     
    class Parent
    {
    	private:
     
    		std::vector< Child * > m_children;
     
    	public:
     
    		Parent (void);
    		~Parent (void);
     
    		bool attachChild (Child * oneChild); // Appel de oneChild->setParent(this);
    }
    Donc l'idée, c'est que quand j'ai un Parent, je lui attache un Child avec la méthode attachChild(). Dans cette méthode, j'appel setParent(this) pour créer le lien de Child vers Parent.

    Par contre, quand j'utilise getParent(), j'ai directement dans la méthode une "segmentation fault" au moment du "return m_myParent;"

    Alors j'imagine que la manière dont je m'y prend doit être bancale.
    Mais comment peut-on faire ce genre de mécanisme ?

    Merci d'avance.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    il faudrait voir plus de code que cela..
    Ce que tu présentes ne montres rien du tout.
    Par contre tu peux faire mieux en ne réalisant que des forward declaration dans tes header.
    Et en corrigeant la déclaration d'une class qui se termine par un ;

    edit: d'ailleurs il n'est pas possible d'avoir une segfault sur un return m_myParent;, le pointeur retourné pourra être incorrect, mais c'est à son utilisation que la segfault se montrera.
    Donc il y a fort à parier que tu veuilles utiliser ce pointeur avant son initialisation. Ou qu'il soit détruit entre temps.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    En général, la structure adopté est plutot l'opposée. Comme le lien fils vers père est utile au fils, à lui de le gérer. Comme il est obligatoire et unique du point de vue du fils, autant le rendre structurel.

    Personnellement, j'en fais toujours une propriété de construction.
    Dans le domaines des interfaces graphiques, nul n'imagine un bouton sans fenêtre...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    explicit Child::Child(Parent* p):parent(p){
    if(p==null_ptr) throw MySpecialError();
    p->addChild(this);
    }
     
    Parent::addChild(Child* child){
        children.push_back(child);
    }
    cela permet de garantir qu'un enfant a et connait son parent, et que le parent recoit son fils.

    Si maintenant, tu souhaites déplacer un enfant d'un parent à un autre, il faut définir une nouvelle méthode
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void Child::moveTo(Parent* p){
        if(p==null_ptr) throw MySpecialError();
        p->addChild(this);
        parent->removeChild(this);
        parent=p;
    }
    Cela fait que le parent ne gère pas ses enfants (dans la vie, c'est un étrange, mais dans les UI, c'est valable...)

    Ce problème est proche de celui du pattern Composite:
    Le conteneur n'a pas à manipuler spécifiquement les contenus
    Logiquement, le conteneur mappe toutes ses méthodes par "for(auto e:contenus) c.<toutes les fonctions>", il n'a donc rien à savoir des contenus.

    Le contenu, par contre, peut avoir à faire de son conteneur.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  4. #4
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 70
    Points : 50
    Points
    50
    Par défaut
    Merci pour les réponses.

    Donc le concept parent/enfant induit un peu en erreur... Dans mon cas, l'enfant n'est pas obligatoirement attaché a un parent en fait.

    C'est plutôt le concept attaché/détaché qui m'intéresse.

    Pour être un peu plus claire, j'aime bien la notion du moteur d'ogre 3D avec les sceneNodes.

    C'est-a-dire qu'on a un arbre de sceneNodes bien propre avec une vraie relation parent/enfant. De plus, chaque sceneNode contient une position dans l'espace.

    A ces sceneNodes on attache pratiquement tout ce qu'on veut. Une lampe, un objet, une camera, etc ...

    Le truc que j'ai du mal à convevoir, c'est qu'on peut questionner directement un objet pour connaitre sa position.

    Donc j'imagine que l'objet questionne son sceneNode pour savoir où il se trouve.

    Vous voyez ?

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par le_ptit_lutin Voir le message
    Le truc que j'ai du mal à convevoir, c'est qu'on peut questionner directement un objet pour connaitre sa position.

    Donc j'imagine que l'objet questionne son sceneNode pour savoir où il se trouve.

    Vous voyez ?
    Je ne vois pas ce que tu trouves extraordinaire là-dedans ?
    Ton objet a une position, et peut-être un parent. Son parent a une position, et peut-être un parent. etc...
    A partir de l'objet tu peux donc très facilement récupérer sa position relative à la sceneNode, ou absolue en récupérant et computant chaque parent.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  6. #6
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 70
    Points : 50
    Points
    50
    Par défaut
    Ben admettons que j'ai une camera.

    Je souhaite la déplacer. Mais la camera elle-même n'a pas sa position.
    Donc dans un premier temps, on parcourt l'arbre des sceneNodes jusqu'a
    celui qui content la camera. Et on applique les mouvements.

    Seulement, je ne trouve pas ça super élégant.

    J'aimerais avoir un pointeur sur ma camera active (si j'en ai plusieurs) et pouvoir changer sa position et changer des paramètres sur la camera (zoom par exemple). Mais sans devoir explicitement appeler l'arbre.

    Mais le problème, quand je part de ma camera pour recuperer le node, j'ai un crash sur le return.

    L'envoi de l'adresse du node se fait correctement (je le print en console).

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par le_ptit_lutin Voir le message
    Mais la camera elle-même n'a pas sa position.
    et ça te semble logique ?
    Si la caméra doit se (dé)placer, elle doit avoir une position. Et qui de mieux que la caméra elle-même pour avoir cette position ?

    La scène n'en a strictement rien à faire de la position des objets. Un objet a une position, et quand on rend la scène elle parcourt ses objets pour récupérer leur position et faire ce qu'elle a à faire.

    Citation Envoyé par le_ptit_lutin Voir le message
    Mais le problème, quand je part de ma camera pour recuperer le node, j'ai un crash sur le return.

    L'envoi de l'adresse du node se fait correctement (je le print en console).
    Une adresse sera toujours correcte. Tu peux faire le print de l'adresse de ton choix ça fonctionnera.
    Si l'adresse que tu récupères est pourrie, l'afficher dans la console ne plantera pas le programme.

    On en revient à mon premier message donc..
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  8. #8
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 70
    Points : 50
    Points
    50
    Par défaut
    Ben si j'ai décidé d'utiliser un arbre pour disposer ma scène c'est pas pour la déco...
    C'est pour gèrer l'occlusion et pouvoir laisser tomber facilement une partie de la scène au rendu.
    C'est pour ça que les positions sont aux nodes et pas aux objets.

    De plus, si je veux une camera, avec la torche activé, et qu'en fait c'est un personnage.
    Ils se partagent tous le même node.

    Et j'ai pas forcément envie de duppliquer la position.

    Et donc oui, ça me semble logique.

    Voila vraiment le code (je voulais juste pas embrouiller) :

    Node.hpp
    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
     
    #ifndef __VACUUM_NODE_H__
    #define __VACUUM_NODE_H__
     
    /* Emeraude commons rules */
    #include "../../Commons/Commons.hpp"
     
    #include <vector>
     
    #include "../../Libs/Math3D/Math3D.hpp"
     
    #include "Entity.hpp"
    #include "../Graphic/Mesh.hpp"
    #include "Camera.hpp"
     
    namespace Engine
    {
    	namespace Vacuum
    	{
    		class Node
    		{
    			private:
     
    				/* === Private typedefs === */
     
     
     
    				/* === Private members === */
     
    				// Hierarchy
    				Node * m_parent;
    				std::vector< Node > m_children;
     
    				// Position
    				Libs::Math3D::Coordinates m_coords;
     
    				// Content
    				std::vector< Engine::Vacuum::Entity * > m_entitiesLink;
     
    			public:
     
    				/* === Public constructors & destructors === */
     
    				Node (void);
    				~Node (void);
     
    				/* === Public getters methods === */
     
    				Node * getParent (void);
    				const Node * getParent (void) const;
     
    				unsigned int getChildrenCount (void) const;
    				Node * getChild (unsigned int index);
    				const Node * getChild (unsigned int index) const;
     
    				Libs::Math3D::Coordinates & getCoordinates (void);
    				const Libs::Math3D::Coordinates & getCoordinates (void) const;
     
    				/* === Public processing methods === */
     
    				Node * createChild (void);
     
    				bool attachEntity (Engine::Vacuum::Entity * entity);
    		};
    	} // end of namespace
    } // end of namespace
     
    #endif /* __VACUUM_NODE_H__ */
    Node.cpp
    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
     
    #include "Node.hpp"
    #include "../../Commons/MemoryManagerDebugger.hpp"
     
    namespace Engine
    {
    	namespace Vacuum
    	{
    		using namespace Libs;
     
    		/* === Public constructors & destructors === */
     
    		Node::Node (void)
    			: m_parent(nullptr), m_children(), m_coords(), m_entitiesLink()
    		{
     
    		}
     
    		Node::~Node (void)
    		{
     
    		}
     
    		/* === Public getters methods === */
     
    		Node * 
    		Node::getParent (void)
    		{
    			return m_parent;
    		}
     
    		const Node * 
    		Node::getParent (void) const
    		{
    			return m_parent;
    		}
     
    		unsigned int 
    		Node::getChildrenCount (void) const
    		{
    			return m_children.size();
    		}
     
    		Node * 
    		Node::getChild (unsigned int index)
    		{
    			if ( index > m_children.size() )
    				return nullptr;
     
    			return &(m_children[index]);
    		}
     
    		const Node * 
    		Node::getChild (unsigned int index) const
    		{
    			if ( index > m_children.size() )
    				return nullptr;
     
    			return &(m_children[index]);
    		}
     
    		Math3D::Coordinates & 
    		Node::getCoordinates (void)
    		{
    			return m_coords;
    		}
     
    		const Libs::Math3D::Coordinates & 
    		Node::getCoordinates (void) const
    		{
    			return m_coords;
    		}
     
    		/* === Public processing methods === */
     
    		Node * 
    		Node::createChild (void)
    		{
    			m_children.push_back(Node());
     
    			return &(m_children.back());
    		}
     
    		bool 
    		Node::attachEntity (Engine::Vacuum::Entity * entity)
    		{
    			m_entitiesLink.push_back(entity);
    			entity->setParentNode(this);
     
    			return true;
    		}
    	} // end of namespace
    } // end of namespace
    Entity.hpp
    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
    49
    50
    51
    52
    53
    54
    55
    56
     
    #ifndef __VACUUM_ENTITY_H__
    #define __VACUUM_ENTITY_H__
     
    /* Emeraude commons rules */
    #include "../../Commons/Commons.hpp"
     
    #include <iostream>
     
    namespace Engine
    {
    	namespace Vacuum
    	{
    		class Node;
     
    		class Entity
    		{
    			public:
     
    				/* === Public enum and constants === */
     
    				enum EntityType
    				{
    					Mesh,
    					AudioSource,
    					LightSource,
    					Camera
    				};
     
    			private:
     
    				/* === Private members === */
     
    				EntityType m_entityType;
    				Node * m_parentNode;
     
    			public:
     
    				/* === Public constructors & destructor === */
     
    				Entity (EntityType entityType);
    				~Entity (void);
     
    				/* === Public setters methods === */
     
    				void setParentNode (Node * parent);
     
    				/* === Public getters methods === */
     
    				Node * getParentNode (void);
    				const Node * getParentNode (void) const;
    		};
    	} // End of namespace
    } // End of namespace
     
    #endif /* __VACUUM_ENTITY_H__ */
    Entity.cpp
    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
     
    #include "Entity.hpp"
    #include "../../Commons/MemoryManagerDebugger.hpp"
     
    namespace Engine
    {
    	namespace Vacuum
    	{
    		/* === Public constructors & destructor === */
     
    		Entity::Entity (EntityType entityType)
    			: m_entityType(entityType), m_parentNode(nullptr)
    		{
     
    		}
     
    		Entity::~Entity (void)
    		{
     
    		}
     
    		/* === Public setters methods === */
     
    		void 
    		Entity::setParentNode (Node * parent)
    		{
    			m_parentNode = parent;
    		}
     
    		/* === Public getters methods === */
     
    		Node * 
    		Entity::getParentNode (void)
    		{
    			return m_parentNode; // <====== CRASH !
    		}
     
    		const Node * 
    		Entity::getParentNode (void) const
    		{
    			return m_parentNode;
    		}
    	} // End of namespace
    } // End of namespace
    Voila voila, donc ca crash là : Node * Entity::getParentNode (void);

  9. #9
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    A priori, c'est que ton pointeur m_parent est faux.

    en fait, c'est tout a fait logique, puisqu'a priori, le pointeur stoqué est une copie d'un autre pointeur, qui lui a pu changer.

    Quand j'ai ce problème, la solution a toujours été de supprimer le pointeur, et de trouver un autre moyen de faire. Ca peut être tout simple ou un profond remaniement structurel.

    Comme je le disait dans une discussion en C il y a quelque jours:

    Un pointeur en moins est une source d'erreurs en moins
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  10. #10
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 70
    Points : 50
    Points
    50
    Par défaut
    Mais donc, ça n'a rien avoir le fait que la class Entity manipule un pointeur sur Node dont il ne connaît rien ?

    En fait, c'est surtout de ça que j'aimerais être sur.

    Parce que comme la signalé Bousk, même si le pointer n'est pas juste, pourquoi le crash se produit sur le return ? Par exemple si j'essaie de printer le pointeur juste avant de le retourner, ca crash aussi.

  11. #11
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 70
    Points : 50
    Points
    50
    Par défaut
    Bon, c'est moi qui est fait l'andouille. Je manipulais un pointeur sur une valeur moisie... Donc l'objet camera se trouvait dans sur une zone mémoire non autorisée, et c'est l'accès au membre "m_parentNode" qui déclenchait le segfault.

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

Discussions similaires

  1. Problème forward declaration
    Par gregleboss50 dans le forum Langage
    Réponses: 10
    Dernier message: 08/08/2014, 07h20
  2. Problème de "forward declaration"
    Par oodini dans le forum C++
    Réponses: 8
    Dernier message: 09/03/2009, 18h05
  3. Problème déclaration anticipée (forward declaration)
    Par lilmeth dans le forum Débuter
    Réponses: 4
    Dernier message: 05/11/2008, 02h02
  4. [Servlet] Problème requestDispacher.forward et CSS
    Par K-Kaï dans le forum Servlets/JSP
    Réponses: 1
    Dernier message: 06/07/2006, 12h58
  5. [JSP] Problème avec forward et param
    Par seb55555 dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 13/12/2004, 12h13

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