bonjour,
pourquoi on forward la declaration d'une class
Merci
bonjour,
pourquoi on forward la declaration d'une class
Merci
Salut,
Le compilateur lit le code source un peu � la mani�re dont tu lis ton roman pr�f�r�: de haut en bas.
Lorsqu'il arrive � la ligne X, il "connait" donc tous les symboles qui ont �t� d�clar�s jusqu'� la ligne X-1, mais il n'a aucune connaissance de ce qui se trouvent... aux lignes suivantes.
Or, on ne peut utiliser que ce que le compilateur connait d�j�, sous peine d'avoir un message d'erreur proche de "XX ne repr�sente pas un type".
En effet, lorsque tu souhaite instancier un objet, tu dois veiller � ce que le compilateur ... connaisse le type de l'objet:
Non seulement, le compilateur doit savoir qu'il existe un type nomm� NomType, par exemple, mais, pour pouvoir instancier un objet, il doit savoir... la taille que cet objet va utiliser en m�moire.
Evidemment, si tu veux invoquer une fonction membre depuis cet objet, il faudra que le compilateur... sache que cette fonction membre existe...
Le probl�me vient lorsque l'on doit cr�er deux types particuliers qui... font r�f�rence l'un � l'autre...
En effet, si tu as une classe (ou une structure) A et une classe (ou une structure) B, que A utilise B et que B utilise A, il y aura, fatalement, une classe qui sera... d�finie avant l'autre...
Par chance, lorsque le compilateur n'a aucun besoin de connaitre l'espace m�moire utilis� par un type donn� ni les membres et fonctions membres dont il est compos�, il peut se contenter de savoir "qu'il existe" un type portant un nom donn�.
Il y a deux cas dans lesquels le compilateur peut se contenter de connaitre l'existence d'un type donn�:
Lorsque l'on utilise un pointeur vers un objet du type indiqu�, parce qu'un pointeur n'est jamais qu'une adresse m�moire � laquelle on trouvera l'objet r�ellement concern� et qu'une adresse m�moire a une taille fixe.
Lorsque l'on utilise une r�f�rence vers un objet du type indiqu�, parce que, lorsque l'on s'int�resse au code binaire (ou assembleur) g�n�r� par l'utilisation d'une r�f�rence, on se rend compte qu'il est strictement identique... � celui utilis� par les pointeurs.
Cependant, le seul fait de savoir qu'il existe des types nomm�s, pour reprendre l'exemple ci-dessus, A et B, ne sera suffisant que tant... qu'on essayera pas d'acc�der au contenu d'un objet de type A ou B.
En effet, si on souhaite acc�der � un membre ou � une fonction membre du type A, le compilateur devra... savoir que le type ou la fonction en question existe, et donc, disposer de la d�finition compl�te de la classe.
Par contre, s'il s'agit, simplement, de d�clarer, dans A, un membre qui soit un pointeur ou une r�f�rence vers un objet de type B ou une fonction membre prenant en argument un pointeur ou une r�f�rence vers un objet de type A, le seul fait que le compilateur sache qu'il existe "un type nomm� A (ou B)" sera largement suffisant.
La mani�re de s'y prendre pour indiquer simplement au compilateur"qu'il existe un type nomm� A (ou B)" s'appelle... la d�claration anticip�e (forward declaration).
Ainsi, nous pouvons envisager d'�crire les fichiers d'en-t�te suivants:
A.h
B.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
16
17 /* directives permettant d'éviter les inclusions multiples */ #ifndef A_H #define A_H class B; //déclaration anticipée de B class A { public: A(); ~A(); void foo(B &); // on n'utilise pas vraiment B ici: on indique "juste" // que foo a besoin d'une référence vers un B void doSomething(); private: B * my_b; // la taille d'un pointeur est connue... // typiquement, elle est de 32 ou 64 bits sur PC }; #endif // fin de la directive contre les inclusions multiples
Par contre, pour pouvoir manipuler le type A au d�part du type B (ou invers�ment), nous devons veiller � ce que le compilateur... sache de quoi sont compos� aussi bien les A que les B.
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 /* directives permettant d'éviter les inclusions multiples */ #ifndef B_H #define B_H class A; //déclaration anticipée de A class B { public: void foo(A &); // on n'utilise pas vraiment A ici: on indique "juste" // que foo a besoin d'une référence vers un A private: A * my_a; // le compilateur se contente de savoir qu'il existe // qu'il existe un type nommé A }; #endif // fin de la directive contre les inclusions multiples
Il faudra donc veiller � inclure les deux fichiers dans t�te dans les fichiers d'impl�mentation:
A.cppB.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 #include <A.h> // pour disposer de la définition de A #include <B.h> // pour disposer de la définition de B void A::foo(B& ref) { ref.foo(*this); //c'est ici que l'on a besoin de la définition de B } A::A():my_b(new B) // ou ici... { } A::~A() { delete my_b; } void A::doSomething() { /*... n'utilise pas forcement my_b, mais peut le faire ;) */ }
Pour conclure, nous pouvons �pingler le fait que, en plus de permettre de r�soudre les probl�mes li�s � ces "d�pendances circulaires", les d�clarations anticip�es permettent de respecter plus facilement la loi demeter.
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7 #include <B.h> // pour disposer de la définition de B #include <A.h> // pour disposer de la définition de A void B::foo(A& ref) { ref.doSomething; //c'est ici que l'on a besoin de la définition de A }
Cette loi indique en effet que si une classe A utilise une classe B et que B utilise une classe C, la classe A ne devrait avoir aucune connaissance de la classe C (ou du moins, ne devrait pas pouvoir manipuler un objet de type C).
Si tu fait une d�claration anticip�e de C dans B.h, et que tu inclues B.h (sans inclure C.h) dans A.h (ou dans A.cpp), toute tentative d'acc�der � un des membres de C au d�part d'une fonction membre de A se soldera... par une erreur de compilation![]()
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
merci beaucoup koala01.
c'est la meilleur r�ponse que j'ai eu depuis que je me suis inscris au forum.
Partager