include croisé

include croisé - C++ - Programmation

Marsh Posté le 23-11-2004 à 12:39:14    

Salut
 
J'ai une petit problème concernant les inclusions croisée ou circulaire
Je me doute que ce point à déjà été traité plusieurs fois mais mes recherches n'ont rien révélé
 
En fait voici mon bout de code
 

Code :
  1. #ifndef COURS_H
  2. #define COURS_H
  3. #include "Eleve.h"
  4. class Cours{
  5. private:
  6. propriété....
  7. public:
  8. void deplacerCours(Heure uneheure);
  9. vector<Eleve*> listerLesElevesInscrits();
  10. };
  11. #endif


 
et un autre fichier
 
 

Code :
  1. #ifndef ELEVE_H
  2. #define ELEVE_H
  3. #include "Cours.h"
  4. class Eleve{
  5. private:
  6. propriété....
  7. public:
  8. vector<Cours*> listerLesCours(JOUR unJourDeLaSemaine);
  9. friend void Cours::deplacerCours(Heure uneheure);
  10. };
  11. #endif


 
 
Mon problème vient du fait que void deplacerCours(Heure uneheure);
est une fonction amie de Eleve et que ça ne compile pas car le compilateur me dit que Cours n'est pas un type.
Bien sur si j'ôte l'include dans Eleve.h et le remplace par class Cours;
il y a aussi une erreur
 
Merci de m'avoir lu et de tenter de me repondre

Reply

Marsh Posté le 23-11-2004 à 12:39:14   

Reply

Marsh Posté le 23-11-2004 à 12:41:07    

utilise le forward-declaration :
 
 

Code :
  1. #ifndef COURS_H
  2. #define COURS_H
  3. class Eleve;
  4. class Cours{
  5. private:
  6. propriété....
  7. public:
  8. void deplacerCours(Heure uneheure);
  9. vector<Eleve*> listerLesElevesInscrits();
  10. };
  11. #endif



---------------
-( BlackGoddess )-
Reply

Marsh Posté le 23-11-2004 à 13:26:00    

Effectivement, étant donné que tu n'utilise pas l'objet Eleve mais seulement un pointeur sur celui-ci, tu peux te contenter de déclarer Elève comme une classe, sans plus de précision sur ses méthodes.
En fait, en un sens, ta double inclusion apportait chaque fois plus d'information à une classe qu'il n'éatit nécessaire pour la construire !

Reply

Marsh Posté le 24-11-2004 à 08:10:43    

OK  
 
Dans ce cas là ça m'arrange
Mais supposons un cas ce n'est pas un pointeur mais un objet qui est renvoyer, je ne croie pas que ça marche
 
En fait même si j'utilise dans Cours.h un type de Eleve par exemple Eleve::ETAT il y a une erreur avec  
class Eleve;
 

Reply

Marsh Posté le 24-11-2004 à 09:33:42    

bin fait l'inverse ... (une forward declaration de Cours dans Eleve.h)
 
le compilo compile linéairement, des qu'il croise un nom qu'il ne connait pas, il fait une erreur.


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 24-11-2004 à 10:11:36    

Je me suis mal exprimé
 
Si j'ai besoins dans les deux header d'un type de l'autre classe
 
C'est tordu je sais mais ça doit bien arrivé

Reply

Marsh Posté le 24-11-2004 à 10:20:59    

il ne me semble pas que ce soit possible ... comment voudrais tu que le compilo s'y retrouve ? ca te permettrait d'écrire "class c1 {c2 c}; class c2{c1 c};" comment serait-il possible de créer un tel objet ?
 
tu n'as peut-être pas bien segmenté des tâches ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 24-11-2004 à 13:00:27    

Je te remercie
 
En fait j'avais préalablement écrit un forward-declaration du type  

Code :
  1. class X;
  2. void X::methode1();


puis j'avais tapé ma classe qui utilisait "X::methode1()" en pensant que la déclaration serait résolue par le linker
 
Merci de tes éclaircissements  
C'est donc impossible


Message édité par darknagash le 24-11-2004 à 13:04:01
Reply

Marsh Posté le 07-06-2005 à 03:31:58    

Bonjour,  
je remonte ce vieux post car j'ai le meme probleme, sauf que la forward declaration ne resoud pas tout pour moi.
Donc voici le principe: J'aila class divertPacket qui a en attribut un pointeur vers un objet de la classe EmulationNode. Et dans la classe EmulationNode, j'ai besoin d'un pointeur vers un objet de la classe divertPacket.
J'ai fait une forward declaration dans la classe EmulationNode, ce qui me resoud la plupart des problemes...sauf quand j'utilise une methode de la classe divertPacket. Enfin, du code valant plus ques des mots,je vous copies les deux headers et le bout de code du cpp qui refuse obstinement de compiler.
PS: Je viens du monde java, donc il est fort possible que j'ai fait des include a la place de forward definition et inversement
 

Code :
  1. #ifndef _EMU_H_
  2. #define _EMU_H_
  3. #include "EmulationPacket.h"
  4. #include "EmulationNode.h"
  5. #include "EmulationAction.h"
  6. #define DIVERT_PORT 4000
  7. #define BUFSIZE 65535
  8. class EmulationNode;
  9. class divertPacket{
  10. private:
  11. EmulationPacket* currentPacket; //Object used to store the buffer and information about the packet
  12. EmulationNode* experimentRules; //The model used with the experiment
  13. unsigned char dataBuffer[BUFSIZE]; //The memory zone used
  14. unsigned long bufferLength; //Size of the buffer
  15. int psock; //The socket
  16. struct sockaddr_in paddr; //The address
  17. public:
  18. divertPacket();
  19. void setBufferLength(unsigned long newLength);
  20. void handleOutput(int fd,EmulationPacket* pdu,EmulationAction* action);
  21. void handleInput(int sock);
  22. void receivePackets();
  23. };
  24. int main();
  25. #endif //_EMU_H_


 

Code :
  1. #ifndef _EMULATIONNODE_H_
  2. #define _EMULATIONNODE_H_
  3. #include "EmulationAction.h"
  4. #include "EmulationPacket.h"
  5. class divertPacket;
  6. class EmulationNode
  7. {
  8. private:
  9. divertPacket* packetSender;
  10. public:
  11. EmulationNode(divertPacket* divert);
  12. ~EmulationNode();
  13. //Method telling the emulation Processor if the packet has to experiment impairments or not
  14. void newEmulationPacket(EmulationPacket * pdu,int sock);
  15. //Method sending the signal associated with the rule to the Finite State Machine
  16. int getSignal(EmulationPacket* pdu);
  17. };
  18. #endif //_EMULATIONNODE_H_


 
Et ca plante juste la:

Code :
  1. void EmulationNode::newEmulationPacket(EmulationPacket * pdu,int sock)
  2. {
  3. EmulationAction* actionToApply;
  4. //Should lookup in the packet and decide wich action to do
  5. actionToApply=new EmulationAction("loss" );
  6. packetSender->handleOutput(sock,pdu,actionToApply);
  7. }


 
S'il vous plait, ne me tapez pas trop fort devant le vide abissal de ma connaissance du C++, j'ai réellement tout testé.
 
Merci d'avance à tous, bonne journée

Reply

Marsh Posté le 07-06-2005 à 09:24:44    

lorsque tu appelles une méthode (packetSender->handleOutput) d'une classe, celle ci doit etre définie completement. donc au début de ton .cpp, il faut inclure tout les .h qui vont bien.


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 07-06-2005 à 09:24:44   

Reply

Marsh Posté le 07-06-2005 à 12:37:32    

Merci beaucoup! Ca marche maintenant. J'etais pas pres de trouver un truc aussi con. Merci encore!


Message édité par fff7878 le 07-06-2005 à 12:38:04
Reply

Marsh Posté le 16-06-2015 à 07:23:20    

Bonjour,
 
Il n'existe qu'une seule façon pour résoudre le problème des dépendance croisées. Il s'agit de mettre la définition des classe (juste leurs noms) au début, en suite la définition de leurs structures (attributs et entêtes des fonctions) et en suite le code des fonctions. Le principe est que pour définir une classe (sa structure), le compilateur a uniquement besoin que les noms de classes soient déclarés, et que pour définir le code des fonctions, il faut que tous les type des paramètres soient définit (mais toute la structure du type dans ce cas là et non seulement son nom). Voici un petit exemple pour illustrer ça.
 
Si vous mettez ceci :
 

Code :
  1. class a;
  2. class b;
  3. class A
  4. {
  5. private:
  6.    B* bb;
  7. public:
  8.    void print()
  9.    {
  10.       bb->print();
  11.    }
  12. };
  13. class B
  14. {
  15. private:
  16.    A* aa;
  17. public:
  18.    void print()
  19.    {
  20.       aa->print();
  21.    }
  22. };


 
Pour l'appel à la méthode print() de la classe A à partir de la classe B, ceci va fonctionner, parce que la classe A était défini structurellement avant cet appel. Par contre, pour l'appel à la méthode print() de la classe B à partir de la classe A, ceci ne pourra pas fonctionner, parce que le compilateur a besoin d'au moins la définition structurelle de la classe B, ce qui n'était pas encore le cas au moment de cet appel. Donc la solution est de mettre les définitions de toutes les classes au début, et ensuite écrire les codes des fonctions associée. Et non pas comme on nous apprend habituellement de faire, c'est à dire la définition de la première classe ensuite le code de ses fonctions, après la définition de la deuxième et classe et ensuite le code de ses fonction ....  
 
Il est à noter que sans ces appels là, le code aurait fonctionner, parce que pour la définition structurelle seulement, le compilateur a juste besoin que les noms des classes soit déclaré auparavant, ce qui était le cas. Mais on ne peut pas faire plus que ça. C'est ce que l'on trouve habituellement dans les forums comme réponse à cette question, en disant qu'on peut uniquement référencer les type, mais pas les utiliser. Mais la question est : pourquoi les référencer si ce n'est pas pour les utiliser !
 
Le code suivant va donc fonctionner
 

Code :
  1. class a;
  2. class b;
  3. class A
  4. {
  5. private:
  6.    B* bb;
  7. public:
  8.    void print();
  9. };
  10. class B
  11. {
  12. private:
  13.    a* aa;
  14. public:
  15.    void print();
  16. };
  17. void a::print()
  18. {
  19.    bb->print();
  20. }
  21. void b::print()
  22. {
  23.    aa->print();
  24. }


 
Ici, au moment de l'appel de chacune des deux fonctions print, les classes associé sont entièrement déclarées, et donc le compilateur peut faire les vérifications associé.
Ce problème est en fait une limitation du compilateur C++, qui ne prend pas le code dans son ensemble, mais ligne par ligne. Ceci fait qu'on peut pas par exemple écrire le main au début d'un ficher, avant les fonctions appelées.  
Un tel problème ne se pose par exemple pas dans un compilateur C# qui cherche dans l'ensemble du code.
 
Maintenant, dans le cas plus concret, ou les classes sont écrites dans fichiers séparés,  la classe A dans le fichier A.h et la classe B dans le ficher B.h. Ceci pose un problème supplémentaire, en plus des références croisées, qui est les inclusions croisées. Bien sur à cause du fait que le chacun des deux fichiers doit inclure l'autre. La solution est donc de ne pas inclure les fichiers entêtes dans chaque fichiers qui en a besoin, mais de les inclure tous au même endroit (dans la partie main par exemple), et ensuite d'inclure les cpp. Ceci peut être fait de la façon suivante :
 

Code :
  1. #include "A.h"
  2. #include "B.h"
  3. #include "A.cpp"
  4. #include "B.cpp"
  5. int main (void)
  6. {
  7.    ...
  8. }


 
 
 

Reply

Marsh Posté le 16-06-2015 à 13:37:58    

ah c'est super de déterrer un topic vieux de 10 ans pour donner la même réponse qui avait été donnée directement en premier lieu ...


---------------
last.fm
Reply

Marsh Posté le 21-07-2015 à 03:10:01    

Edit: 10 ans.


Message édité par zangdaarr le 21-07-2015 à 03:10:25
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed