[C++] Problèmes à la compilation avec des fonctions amies

Problèmes à la compilation avec des fonctions amies [C++] - C++ - Programmation

Marsh Posté le 26-09-2003 à 18:13:00    

Salut à tous !
 
Je programme en C++ sous Linux à l'aide gcc. Et j'ai un petit problème à la compilation. Voici mon soucis :
 
J'ai une classe CSOFT_scene et une classe CLine. Cette dernière possède une fonction membre DrawLine, que je souhaite rendre amie avec la classe SOFT_scene. Voici comment je m'y suis pris :
 
Classe CLine (fichier CLine.h)

Code :
  1. class CLine {
  2.      [...]
  3.      void DrawLine(CSOFT_scene* ) ; /* Ligne 14 */
  4.      [...]
  5. };


 
Classe CSOFT_scene (fichier CSOFT_scene.h)

Code :
  1. class CSOFT_scene {
  2.       [...]
  3.       friend void CLine::DrawLine(CSOFT_scene* ) ; /* Ligne 15 */
  4.       [...]
  5. };


 
Voici le résultat de la compilation :
 
Résultat de la compilation


g++ -Wall -pedantic  -c main.cpp -o main.o
In file included from CLine.h:7,
                 from main.cpp:4:
CSOFT_scene.h:15: variable or field `CLine' declared void
CSOFT_scene.h:15: `CLine' is neither function nor member function; cannot be declared friend
CSOFT_scene.h:15: syntax error before `::' token
make: *** [main.o] Error 1


 
J'ai l'impression qu'il s'agit d'un simple problème de syntaxe :/
 
Je rajoute mon makefile :
 
Makefile


CC=g++
SDL = -lSDL
CFLAGS = -Wall -pedantic
CMATH = -lm
CDEBUT = -g
COPT = -O3
CPROG = resultat
 
 
std: main.o CLine.o CSOFT_scene.o
 $(CC) $(SDL) $(CFLAGS) $(CMATH) main.o CLine.o CSOFT_scene.o -o $(CPROG)
 
main.o: main.cpp
 $(CC) $(CFLAGS) -c main.cpp -o main.o
 
CLine.o: CLine.cpp
 $(CC) $(CFLAGS) -c CLine.cpp -o CLine.o
 
CSOFT_scene.o: CSOFT_scene.cpp
 $(CC) $(CFLAGS) -c CSOFT_scene.cpp -o CSOFT_scene.o
 
 
clean:
 rm -f resultat *.o
 


 
 
Merci pour votre aide !
 
@+
 
Edit 1 : Changement du résultat de la compilation, désolé.
Edit 2 : Rajout du makefile


Message édité par Evadream -jbd- le 27-09-2003 à 20:31:46
Reply

Marsh Posté le 26-09-2003 à 18:13:00   

Reply

Marsh Posté le 26-09-2003 à 18:20:10    

hmmm tu ne peut pas declarer UNE methode d'une classe friend d'une autre.
 
Faut declarer une CLASSE friend de l'autre.
 
Classe CLine (fichier CLine.h)

Code :
  1. class CLine {
  2.     [...]
  3.     void DrawLine(CSOFT_scene* ) ; /* Ligne 14 */
  4.     [...]
  5. };


 
Classe CSOFT_scene (fichier CSOFT_scene.h)

Code :
  1. class CSOFT_scene {
  2.      [...]
  3.      friend class CLine; /* Ligne 15 */
  4.      [...]
  5. };

Reply

Marsh Posté le 26-09-2003 à 18:29:01    

Ah bon ?  
 
J'ai lu dans "Le langage C++" de notre ami Bjarne Stroustrup :
 
La fonction membre d'une classe peut être l'amie d'une autre. [...]
 
L'exemple qui suit ds le bouquin reprend la même syntaxe que ci-dessus.
 
 

Code :
  1. class List_iterator {
  2.     // ...
  3.     int *next() ;
  4. }
  5. class List {
  6.      friend int* List_iterator::next() ;
  7.      // ...
  8. }


 
"Il n'est pas inhabituel que toutes les fonctions d'une classe  soient amies d'une autre [...]"
 
Et l'exemple qui suit reprend ta syntaxe :
 

Code :
  1. class List {
  2.      friend class List_iterator ;
  3. }


 
 
Que dois-je en conclure ? S'agit t'il d'une erreur ds le bouquin ? (dernière édition)
 
Merci à toi pour ta précédente réponse en tout cas !
 
@+

Reply

Marsh Posté le 26-09-2003 à 18:31:11    

le problème est que la différence entre les dires de notre ami Stroustrup et les spec des compilos est souvent enorme ...
 
tu essaieras la specialisation partielle de fonction tempalte, le mot clé export etc ...
 
Je pense juste que le compilo ne supporte pas les METHODES amieS.
Je vais néanmoins vérifier et tester ca :)
 
 
EDIT : euh tu includ bien le cline.h dans le CSOFT_scene.h ??


Message édité par Joel F le 26-09-2003 à 18:31:47
Reply

Marsh Posté le 26-09-2003 à 18:41:00    

Merci pour ta rapide réponse !
 


le problème est que la différence entre les dires de notre ami Stroustrup et les spec des compilos est souvent enorme ...


 
Je n'en avais naïvement jamais douté ! Pour information, je travaille avec gcc 3.2.3.
 

EDIT : euh tu includ bien le cline.h dans le CSOFT_scene.h ??


 
Oui, je viens de (re)vérifier pour la cinquantième fois de l'après midi [:ddr555]
 
 
J'ai essayé de "passer" la classe CLine en friend comme tu me la proposé, à savoir :
 
Classe CSOFT_scene (fichier CSOFT_scene.h)

Code :
  1. class CSOFT_scene {
  2.     [...]
  3.     friend class CLine; /* Ligne 15 */
  4.     [...]
  5. };


 
 
Mais j'obtiens l'erreur suivante à la compilation, ce qui doit mettre en avant une autre faiblesse de mon code :
 
Résultat de la compilation


g++ -Wall -pedantic  -c main.cpp -o main.o
g++ -Wall -pedantic  -c CLine.cpp -o CLine.o
g++ -Wall -pedantic  -c CSOFT_scene.cpp -o CSOFT_scene.o
In file included from CSOFT_scene.h:9,
                 from CSOFT_scene.cpp:3:
CLine.h:14: `CSOFT_scene' was not declared in this scope
CLine.h:14: syntax error before `)' token
make: *** [CSOFT_scene.o] Error 1


 
Ca semble donc être ici un problème de portée. Mais je ne suis pas du tout sensibilisé à cela. La solution se trouve t'elle ds l'utilisation d'un namespace ?
 
Merci à vous !
 
Edit : je dois m'absenter pour la soirée ! A plus tard !


Message édité par Evadream -jbd- le 26-09-2003 à 18:43:49
Reply

Marsh Posté le 26-09-2003 à 18:51:58    

=> utilise gcc 3.3.1 le 3.2 est une usine a ICE.
 
=> a tu proteger tes .h apr des diretcive d'inclusions ??
 

Code :
  1. // debut du .h
  2. #ifndef _MONFICHIER_H_
  3. #define _MONFICHIER_H_
  4. // mon code
  5. #define

Reply

Marsh Posté le 26-09-2003 à 18:57:08    

l'exemple de base
 

Code :
  1. namespace A
  2. {
  3.   class Bar
  4.   {
  5.   public:
  6.    
  7.     void method() const;
  8.   };
  9. }
  10. namespace B
  11. {
  12.   class Foo
  13.   {
  14.     void method() const;
  15.     friend void A::Bar::method() const;
  16.   };
  17. }
  18. void A::Bar::method() const
  19. {
  20.   B::Foo().method();
  21. }
  22. void B::Foo::method() const
  23. {}
  24. int main()
  25. {
  26.   A::Bar().method();
  27. }


 
passe chez toi ?

Reply

Marsh Posté le 26-09-2003 à 19:00:17    

Bon gcc 3.3.1 compile l'exemple de taz sans broncher ...
 
pe que avec un chti peu plus de code ... on verrait mieux :D

Reply

Marsh Posté le 26-09-2003 à 19:04:11    

Joel F a écrit :

=> utilise gcc 3.3.1 le 3.2 est une usine a ICE.
 
=> a tu proteger tes .h apr des diretcive d'inclusions ??
 

Code :
  1. // debut du .h
  2. #ifndef _MONFICHIER_H_
  3. #define _MONFICHIER_H_
  4. // mon code
  5. #endif   /* j'ai remplacé ton #define par un #endif ;)




 
Oui, tous mes h sont protégés de cette facon ! Merci pour la recommandation du compilo. Comme je suis un peu pressé, je posterai plus de code demain (mais y'a pas grand chose). Je ne l'ai pas fait ici car j'ai pensé que le problème ne pouvait pas provenir d'autre part.  
 
Taz > un grand merci pour ton exemple de base, je verrais tout ca dès que je rentre !
 
Merci à vous deux, à demain.


Message édité par Evadream -jbd- le 26-09-2003 à 19:04:43
Reply

Marsh Posté le 26-09-2003 à 19:06:31    

Taz > J'ai pas résisité et j'ai compilé ton exemple de base, pas de soucis ! Je verrais donc tout ca demain !
 
@+

Reply

Marsh Posté le 26-09-2003 à 19:06:31   

Reply

Marsh Posté le 26-09-2003 à 19:08:07    

remarque : les gardiens d'inclusion, c'est bien, encore faut-il qu'ils soient efficaces ! comprenez bien que vous n'êtes ni le premier, ni le dernier programmeur au monde à écrire un stack.hpp  :non:  alors pour vos motifs, faites un truc bien, mélangez nom du fichier, votre nom, le nom du projet, la date de création, tout ce qui vous passe par la tête (faites vous même un petit script pour automatiser tout ça si ça vous chante).

Reply

Marsh Posté le 26-09-2003 à 19:19:15    

avec celui la je suis tranquille :
 

Code :
  1. #ifndef __FILE_FROM_PROJECT_FILENAME_H__INCLUDED__
  2. #define __FILE_FROM_PROJECT_FILENAME_H__INCLUDED__

Reply

Marsh Posté le 26-09-2003 à 19:22:23    

#pragma once  
 
[:aloy]

Reply

Marsh Posté le 26-09-2003 à 19:26:35    

ca c du pure visual, je pense pas que gcc le supporte :o

Reply

Marsh Posté le 26-09-2003 à 19:28:34    

y devrait, ca resoud tous vos pb de nommage :O
 
 
(au fait, ca t'interessera pe, visu permet de faire du 3dnow & cie direct en C)

Reply

Marsh Posté le 26-09-2003 à 19:35:57    

Joel F a écrit :

ca c du pure visual, je pense pas que gcc le supporte :o


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11569


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 26-09-2003 à 20:52:16    

Taz a écrit :

l'exemple de base
[...]


 
Je suis chez des amis et je passais par là ;)
Je voulais juste savoir si l'utilisation des namespace était LA marche à suivre pour utiliser des classes friends. Je pose cette question car dans toutes les choses que j'ai pu lire, je n'ai pas vu d'allusion à cela pour leur utilisation.
 
Merci !
 

Reply

Marsh Posté le 26-09-2003 à 21:11:49    

non, ce sont deux choses distinctes. de toutes façons, tu est toujours dans namespace que tu nommes ou pas (anomyme ou global).

Reply

Marsh Posté le 26-09-2003 à 21:21:19    

Ok, merci pour la réponse. Cependant, j'ai un peu de mal à faire le lien avec mon problème de portée puisque tu me dis que ce sont des problèmes distincts.  
 

Reply

Marsh Posté le 26-09-2003 à 21:24:08    

franchement, on a besoin de vrai code

Reply

Marsh Posté le 26-09-2003 à 22:18:54    

chrisbk a écrit :


(au fait, ca t'interessera pe, visu permet de faire du 3dnow & cie direct en C)


 
du SSE 2 ???? je crois pas :D

Reply

Marsh Posté le 26-09-2003 à 22:21:27    

Joel F a écrit :


 
du SSE 2 ???? je crois pas :D


 
ben tu devrais [:spamafote]
ca s'apelle les intrinsics, fais une recherche MSDN....
 
par contre je t'explique pas l'esthetisme de la chose [:huit]


Message édité par chrisbk le 26-09-2003 à 22:21:49
Reply

Marsh Posté le 26-09-2003 à 22:23:14    

ah ... alors .... ca me permettrait d'etendre E.V.E. sur Pentium  :sol:

Reply

Marsh Posté le 26-09-2003 à 23:25:47    

Taz a écrit :

franchement, on a besoin de vrai code


 
Ok, je comprends ! Je vous poste ca dès que possible !  
Encore merci pour les réponses !

Reply

Marsh Posté le 27-09-2003 à 13:20:38    

Rebonjour tout le monde ! Après une bonne nuit de sommeil, je vous poste les parties de mon code qui me semblent intéressantes pour venir à bout de mon incompréhension. Mon "projet" s'articule autour de 5 fichiers (6 avec le makefile) : le couple cpp/h de la classe CLine, le couple cpp/h de la classe CSOFT_scene, et un main.cpp. Je poste les parties qui pourraient poser problème.
 
Classe CLine : CLine.h
 

Code :
  1. #ifndef _CLINE_H_26092003
  2. #define _CLINE_H_26092003
  3. #include <iostream>
  4. #include "CSOFT_scene.h"
  5. #include <SDL/SDL.h>
  6. class CLine {
  7. public:
  8.  CLine(int ix=0, int iy=0, int idx=0, int idy=0) : x1(ix), y1(iy), x2(idx), y2(idy) { }
  9.  void DrawLine(CSOFT_scene*) ; /* ligne 14 : erreur à la compilation */
  10. private:
  11.            int x1;
  12.         int y1;
  13.  int x2;
  14.  int y2;
  15. };
  16. #endif


 
Classe CLine : CLine.cpp (parties intéressantes)
 
Il n'y a que ma fonction putpixel, ds laquelle je fais appelle à une CSOFT_scene de la facon qui suit, le reste étant un simple algorithme de tracage de ligne :
 

Code :
  1. #include <SDL/SDL.h>
  2. #include "CLine.h"
  3. void CLine::DrawLine(CSOFT_scene *scene)
  4. {
  5. /* ..... */
  6. scene->putpixel(x,y,255,255,255);
  7. /* ..... */
  8. }


 
Classe CSOFT_scene : CSOFT_scene.h
 

Code :
  1. #ifndef _CSOFT_scene_26092003
  2. #define _CSOFT_scene_26092003
  3. #include <iostream>
  4. #include <string.h> /* manipulation des char* nécessaire pour void SetWindowName(const char*) */
  5. #include <SDL/SDL.h>
  6. #include "CLine.h"
  7. class CSOFT_scene {
  8.     friend class CLine ;
  9. public:
  10.  CSOFT_scene();
  11.  void CreateWindow();
  12.  void SetupPixelFormat();
  13.  void Init();
  14.  void HandleKeyPressEvent(const SDL_keysym*);
  15.  void MainLoop();
  16.  void putpixel(const int x, const int y, const Uint8 R, const Uint8 G,  const Uint8 B) ;
  17.  void Slock() ;
  18.  void Sulock() ;
  19.  void RenderScene();
  20.  void ToggleFullScreen();
  21.  void Quit(const int);
  22.  void CalculateFrameRate();
  23.  int Getheight() const;
  24.  int Getwidth() const;
  25.  int Getdepth() const;
  26.  char* GetWindowName() const;
  27.  void Setheight(const int);
  28.  void Setwidth(const int);
  29.  void Setdepth(const int);
  30.  void SetWindowName(const char*);
  31. private:
  32.  SDL_Surface * screen;
  33.  int VideoFlags;
  34.  int height;
  35.  int width;
  36.  int depth;
  37.  char* WindowName;
  38. };
  39. #endif


 
Classe CSOFT_scene : CSOFT_scene.cpp (parties intéressantes)
 
Je ne vois pas de choses qui pourraient nous intéresser ici

Code :


 
Le main : main.cpp
 

Code :
  1. #include <iostream>
  2. #include <SDL/SDL.h>
  3. #include "CLine.h"
  4. #include "CSOFT_scene.h"
  5. int main(int argc, char* argv[])
  6. {
  7. CSOFT_scene* scene = new CSOFT_scene ;
  8. scene->Init() ;
  9. scene->SetupPixelFormat() ;
  10. scene->Setwidth(640) ;
  11. scene->Setheight(480) ;
  12. scene->Setdepth(32) ;
  13. scene->SetWindowName("SDL Software Scene" );
  14. scene->CreateWindow() ;
  15. getchar();
  16. delete scene ;
  17. }


 
 
Makefile :


CC=g++
SDL = -lSDL
CFLAGS = -Wall -pedantic
CMATH = -lm
CDEBUT = -g
COPT = -O3
CPROG = resultat
 
 
std: main.o CLine.o CSOFT_scene.o
 $(CC) $(SDL) $(CFLAGS) $(CMATH) main.o CLine.o CSOFT_scene.o -o $(CPROG)
 
main.o: main.cpp
 $(CC) $(CFLAGS) -c main.cpp -o main.o
 
CLine.o: CLine.cpp
 $(CC) $(CFLAGS) -c CLine.cpp -o CLine.o
 
CSOFT_scene.o: CSOFT_scene.cpp
 $(CC) $(CFLAGS) -c CSOFT_scene.cpp -o CSOFT_scene.o
 
 
clean:
 rm -f resultat *.o
 
 


 
Résultat de la compilation :


g++ -Wall -pedantic  -c main.cpp -o main.o
g++ -Wall -pedantic  -c CLine.cpp -o CLine.o
g++ -Wall -pedantic  -c CSOFT_scene.cpp -o CSOFT_scene.o
In file included from CSOFT_scene.h:7,
                 from CSOFT_scene.cpp:3:
CLine.h:14: `CSOFT_scene' was not declared in this scope
CLine.h:14: syntax error before `)' token
make: *** [CSOFT_scene.o] Error 1


 
 
Voilà voilà :) Merci à vous !


Message édité par Evadream -jbd- le 27-09-2003 à 20:32:15
Reply

Marsh Posté le 27-09-2003 à 13:42:28    

Dans CLine.hpp, retire le  
 

Code :
  1. #include "CSOFT_scene.h"


 
utilise a la place des forward declaration :
 

Code :
  1. class CSOFT_scene;
  2. class CLine
  3. {
  4. ....
  5. };

Reply

Marsh Posté le 27-09-2003 à 13:43:43    

on a toujours pas le fichier que tu compiles : mais tout ça semble être une inclusion circulaire mal foutue ou finalement il te manque la déclaration dans l'ordre. amuse toi avec g++ -E machin.cpp | less et regarde l'imbroglio


Message édité par Taz le 27-09-2003 à 13:47:10
Reply

Marsh Posté le 27-09-2003 à 13:47:45    

Joel F a écrit :


utilise a la place des forward declaration

correct

Reply

Marsh Posté le 27-09-2003 à 14:11:25    


 
Vous ètes le maillon fort  [:spyer]

Reply

Marsh Posté le 27-09-2003 à 14:50:23    

Taz a écrit :

on a toujours pas le fichier que tu compiles


 
Ca fait un peu boulay, désolé [:ddr555]. Tu parles de CSOFT_scene.cpp ? Je ne l'avais pas mis délibérement parce que je pensais pas que le problème pouvait provenir de là. Je le poste si je n'ai pas réussi à résoudre le problème avec tous les élements que vous m'avez donné.
 

Taz a écrit :

mais tout ça semble être une inclusion circulaire mal foutue ou finalement il te manque la déclaration dans l'ordre. amuse toi avec g++ -E machin.cpp | less et regarde l'imbroglio


 
Ok très bien ! Merci pour le conseil !
 

Joel F a écrit :

Dans CLine.hpp, retire le
 
[...]  
 


 
Ok, je fais ca dès que j'ai accès à mon programme :) Merci !


Message édité par Evadream -jbd- le 27-09-2003 à 14:53:10
Reply

Marsh Posté le 27-09-2003 à 20:09:24    

EDIT : Etourderie ds le makefile. Le g++ -o main.o ... s'est transformé en g++ main.o -o :) Ca va mieux !
 
Hello !
 
Donc, les forward déclarations m'ont permis de mettre fin à mon soucis de compilation (yeahhh, merci !). Par contre, je ne peux apparement pas me passer du
 

Code :
  1. #include "CSOFT_scene.h"


 
dans CLine.h à cause de (je pense)
 

Code :
  1. void DrawLine(CSOFT_scene*) ;


 
L'erreur de compilation, si j'utilise ici une forward déclaration de CSOFT_scene, est alors la suivante :
 


CLine.cpp: In member function `void CLine::DrawLine(CSOFT_scene*)':
CLine.cpp:38: invalid use of undefined type `struct CSOFT_scene'
CLine.h:6: forward declaration of `struct CSOFT_scene'
CLine.cpp:52: invalid use of undefined type `struct CSOFT_scene'
CLine.h:6: forward declaration of `struct CSOFT_scene'
make: *** [CLine.o] Error 1


 
Ca fonctionne avec le #include, donc je n'ai pas de soucis, si ce n'est que je ne comprends pas exactement pourquoi la forward déclaration fonctionne pour CLine et non pour CSOFT_scene.
 
En tout cas, un grand merci à tous pour votre aide et votre patience !
 
@+


Message édité par Evadream -jbd- le 27-09-2003 à 20:33:21
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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