Redefinition de namespace

Redefinition de namespace - C++ - Programmation

Marsh Posté le 05-10-2007 à 16:56:38    

Bonjour,  
 
Je rencontre un comportement curieux à la compilation de plusieurs fichiers.
 
J'ai une fichier Article.H :
 

Code :
  1. class Article
  2. {
  3. public:
  4.   double prix;
  5.   double tva();
  6. };


 
Un fichier Article.C :
 

Code :
  1. #include "Article.H"
  2. double Article::tva()
  3. {
  4.   return (0.196*prix);
  5. }


 
et un fichier main.C :
 

Code :
  1. #include <iostream>
  2. using namespace std;
  3. #include "Article.H"
  4. int main()
  5. {
  6.   Article pomme;
  7.   pomme.prix = 5;
  8.   cout << pomme.tva() << endl;
  9. }


 
Quand je compile séparément les deux fichiers Article.C et main.C puis que j'en réalise l'édition de liens, cela fonctionne parfaitement malgré l'apparition du code de Article.H à deux occasions dans l'executable final (Au début de Article.C et de main.C ).
 
Par contre, si je rajoute un namespace dans Article.H en l'écrivant ainsi :
 

Code :
  1. class Article
  2. {
  3. public:
  4.   double prix;
  5.   double tva();
  6. };
  7. namespace Fruit
  8. {
  9.   double poids;
  10. }


 
Je trouve une erreur de compilation :
 

Code :
  1. main.o(.bss+0x0): multiple definition of `Fruit::poids'
  2. Article.o(.bss+0x0): first defined here
  3. collect2: ld returned 1 exit status


 
Pourtant si la première version de Article avec une redéfiniton des déclarations de Article.H est acceptée à la compilation, la seconde version devrait fonctionner, non ?
 
Quelqu'un pourrait-il m'indiquer ou est le problème et la raison pour laquelle la première version est compilable et pas la seconde ?
Quelle serait la solution à adopter ?
 
D'avance merci de votre aide,

Reply

Marsh Posté le 05-10-2007 à 16:56:38   

Reply

Marsh Posté le 05-10-2007 à 17:43:08    

salut,
il faudrait ajouter:

Code :
  1. #ifndef ARTICLE_H
  2. #define ARTICLE_H
  3. /* ton code de article.h
  4. */
  5. #endif
 


je crois que la différence de comportement vient du fait que poids est alloué en mémoire, alors qu'avant, ce n'était que des définitions.

 

EDIT: trop vite sans faire attention, je le corrige quand meme.


Message édité par tuxce le 05-10-2007 à 17:55:18
Reply

Marsh Posté le 05-10-2007 à 17:49:26    

La commande est :
 

Code :
  1. #ifndef ARTICLE_H


 
et non :
 

Code :
  1. #ifundef ARTICLE_H


 
J'ai déja indiqué ces lignes sans que cela change quelquechose. Je ne les avais pas précisées pour alléger ma question.
Le problème n'est pas résolu avec cette modification.
 
Est-ce que vous connaitriez une solution ?
 
Cordialement,

Reply

Marsh Posté le 06-10-2007 à 00:29:40    

définition != déclaration

Reply

Marsh Posté le 06-10-2007 à 01:40:08    

ce que tu peux faire, c'est déclarer les eventuelles fonctions/classes dans le .h, et les variables, dans le .cc (c'est du c++ ;))

Code :
  1. class Article
  2. {
  3.         public:
  4.                 double prix;
  5.                 double tva();
  6. };
  7. namespace Fruit{};


Code :
  1. #include "article.h"
  2. namespace Fruit
  3. {
  4. double poids=0;
  5. };
  6. double Article::tva()
  7. {
  8. return (0.196*prix);
  9. }


Code :
  1. #include <iostream>
  2. #include "article.h"
  3. using namespace std;
  4. extern double Fruit::poids;
  5. int main()
  6. {
  7. Article pomme;
  8. pomme.prix = 5;
  9. cout << pomme.tva() << endl;
  10. cout << poids << endl;
  11. }


 
mais par contre, je suis pas sur que ca soit indispensable de déclarer une variable global de cette facon!

Reply

Marsh Posté le 08-10-2007 à 09:40:11    

Merci de ces réponses.
J'aimerais comprendre plus précisément quel était mon erreur.
 
Est-ce qu'il y avait une double déclaration de la variable poids du namespace et que cela posait problème ?
Pourtant, quand je déclare la variable prix de la classe Article, elle apparait deux fois à la compilation (dans Article.o et main.o), sans que cela pose problème à l'édition de liens.
 
Pourquoi ce comportement différent ?

Reply

Marsh Posté le 08-10-2007 à 12:01:00    

la variable prix n'est pas allouée, alors que poids si.
aucune instance de Article n'est déclaré dans le article.h.

Reply

Marsh Posté le 08-10-2007 à 13:22:33    

Pour mieux comprendre, ce que tu dis, l'écriture  
 

Code :
  1. class Article
  2. {
  3. public:
  4. double prix;
  5. double tva();
  6. };


 
ne correspondrait pas à une allocation de poids
 
alors que :
 

Code :
  1. namespace Fruit
  2. {
  3. double poids;
  4. }


 
correspondrait à allouer la variable poids ?
 
Est-ce bien cela que tu indiques ?
 
Pourquoi cette différence de comportement ?

Reply

Marsh Posté le 08-10-2007 à 13:36:05    

Je suis pas expert, mais je sais que:

Code :
  1. #include <iostream>
  2. class A
  3. {
  4.   public:
  5.     int x=0;
  6. };
  7. int main ()
  8. {
  9.   std::cout << A::x;
  10.   return 0;
  11. }


provoque une erreur car il n'y a aucune instance de A, ce n'est que la définition de la classe.
 
alors que

Code :
  1. #include <iostream>
  2. namespace A
  3. {
  4.   int x=0;
  5. };
  6. int main ()
  7. {
  8.   std::cout << A::x;
  9.   return 0;
  10. }


fonctionne car x est alloué en mémoire, le namespace ne fait que définir un espace pour les déclarations.

Reply

Marsh Posté le 08-10-2007 à 14:32:57    

Bonjour,
 
Merci de ces différentes précisions.
 
J'ai essayé le code donné plus haut avec les trois fichiers mais cela ne semble pas accepter. D'une part, je ne parviens à définir le namespace en deux parties (d'une part dans Article.H, d'autre part dans Article.cpp. Ensuite, en déplaçant les lignes de code, je conserve un problème sur la non-déclaration ou des déclarations multiples de variables.

Reply

Marsh Posté le 08-10-2007 à 14:32:57   

Reply

Marsh Posté le 08-10-2007 à 14:50:16    

tuxce a écrit :

Je suis pas expert, mais je sais que:

Code :
  1. #include <iostream>
  2. class A
  3. {
  4.   public:
  5.     int x=0;


Illégal.


 
J'aimerais qu'on arrête de traiter le même problème dans 36 sujets. Déclaration != définition. Quelque soit votre membre statique, variable globale dans un namespace ou pas, il vous FAUT:
- .h qui contient la déclaration
- .cpp qui contient la définition et initialisation

Reply

Marsh Posté le 08-10-2007 à 15:13:24    

Je veux bien essayer de revenir à ce sujet mais, dans ce cas, peut-tu donner un exemple simple d'utilisation d'une variable dans un namespace (et non pas d'une méthode). J'ai l'impression qu'il me faut passer par la redefinition d'une classe dans mon namespace pour cela.

Reply

Marsh Posté le 08-10-2007 à 15:25:18    

redéfinition  = illégal

 

a.h
namespace A { extern int x; }

 

a.cpp
namespace A { int x = 42; }

 

et voilà tu peux utiliser A::x partout.


Message édité par Taz le 08-10-2007 à 16:25:31
Reply

Marsh Posté le 08-10-2007 à 15:43:09    

sauf si a.h est inclus dans 2 .cpp différents.
 

nathan_g a écrit :

J'ai essayé le code donné plus haut avec les trois fichiers mais cela ne semble pas accepter. D'une part, je ne parviens à définir le namespace en deux parties (d'une part dans Article.H, d'autre part dans Article.cpp. Ensuite, en déplaçant les lignes de code, je conserve un problème sur la non-déclaration ou des déclarations multiples de variables.


tu peux poster la sortie?
chez moi, ca fonctionne (avec g++ -Wall: pas d'erreur)

Reply

Marsh Posté le 08-10-2007 à 15:52:50    

Tuxce : merci de ce détail (sauf...) qui doit changer pas mal de chose.
 
En l'occurence, de manière simplifiée, mon code qui ne fonctionne pas est :
 
Fichier Article.H
 

Code :
  1. #ifndef  _ARTICLE_
  2. #define  _ARTICLE_
  3. namespace Article
  4. {
  5.   double poids;
  6. };
  7. #endif


 
Fichier Article.C:
 

Code :
  1. #include "Article.H"
  2. namespace Article
  3. {
  4.   double poids = 0.3;
  5. };


 
Fichier main.C
 

Code :
  1. #include <iostream>
  2. using namespace std;
  3. #include "Article.H"
  4. using namespace Article;
  5. int main()
  6. {
  7.   cout << Article::poids << endl;
  8.   return (1);
  9. };


 
La compilation ne fonctionne pas et me sort le message :
 

Code :
  1. Article.C:5: error: redefinition of `double Article::poids'
  2. Article.H:6: error: `double Article::poids' previously declared here


 
Comment donner à tout cela une écriture correcte ?
J'ai du rater quelque chose mais je ne vois pas comment donner une écriture correcte à ce code.

Reply

Marsh Posté le 08-10-2007 à 16:00:20    

ca d'accord...
mais tu as essayé le code avec extern, je t'avais remis les 3 fichiers:
http://forum.hardware.fr/forum2.ph [...] 0#t1620020


Message édité par tuxce le 08-10-2007 à 16:01:33
Reply

Marsh Posté le 08-10-2007 à 16:23:57    

putain je suis fatigué moi... désolé

Reply

Marsh Posté le 08-10-2007 à 16:43:06    

Taz a écrit :

putain je suis fatigué moi... désolé


t'aurais pu rajouter à coté du "fatigué" comme quoi tu as édité le post d'avant en ajoutant le extern ;)
en gros, ca revient à ce que j'ai posté avant!


Message édité par tuxce le 08-10-2007 à 16:43:42
Reply

Marsh Posté le 08-10-2007 à 16:49:41    

Merci Tuxce de ton implication dans mon problème.
 
A moins que j'ai mal compris, j'ai modifié le précédent fichier main.C afin d'y inclure le " extern " ce qui donne le fichier main.C suivant , les deux autres n'étant pas modifiés  :
 

Code :
  1. #include <iostream>
  2. using namespace std;
  3. #include "Article.H"
  4. using namespace Article;
  5. extern double Article::poids;
  6. int main()
  7. {
  8.   cout << Article::poids << endl;
  9.   return (1);
  10. };


 
Malheureusement, cela ne résouds en rien mon problème car le message d'erreur n'est pas modifié. Désolé !

Reply

Marsh Posté le 08-10-2007 à 17:20:14    

il faut modifier les autres aussi:
article.h:

Code :
  1. namespace Fruit {};


article.c:

Code :
  1. namespace Fruit
  2. {
  3.   double poids=0;
  4. };
 


Message édité par tuxce le 08-10-2007 à 18:23:11
Reply

Marsh Posté le 08-10-2007 à 17:33:59    

Bon, sans doute que j'ai un peu de mal ;)
Maintenant, le code est :
 
Article.H
 

Code :
  1. namespace Article {};


 
Article.C :
 

Code :
  1. #include "Article.H"
  2. namespace Article
  3. {
  4.   double poids = 0.3;
  5. };


 
et main.C :
 

Code :
  1. #include <iostream>
  2. using namespace std;
  3. #include "Article.H"
  4. using namespace Article;
  5. extern double Article::poids;
  6. int main()
  7. {
  8.   cout << Article::poids << endl;
  9.   return (1);
  10. };


 
Malheureusement, ca ne compiletoujours pas. Le message est maintenant :
 

Code :
  1. main.C:9: error: `Article::poids' should have been declared inside `Artcle'
  2. main.C: In function `int main()':
  3. main.C:13: error: `poids' is not a member of `Article'
  4. /usr/lib/gcc/i586-mandrake-linux-gnu/3.4.1/../../../crt1.o(.text+0x18):In function `_start':
  5. ../sysdeps/i386/elf/start.S:98: undefined reference to `main'
  6. collect2: ld returned 1 exit status


 
Qu'est ce que j'ai raté ?
Ou est-le problème dans cette nouvelle écriture ?

Reply

Marsh Posté le 08-10-2007 à 18:33:10    

faudra que tu m'expliques pourquoi tu n'as pas pris tel quel l'exemple que je t'ai donnée!!!
 
pour ton programme, il faut modifier:

Code :
  1. cout << Article::poids << endl;


par

Code :
  1. cout << poids << endl;

Reply

Marsh Posté le 08-10-2007 à 18:37:14    

Bonsoir,
 
Merci de cette nouvelle réponse, mais ce que tu proposes ne change absolument rien.
Le message d'erreur reste identique !
 
Peut-tu me confirmer que, de ton coté, la compilation de ces trois fichiers est acceptée et donne un executable fonctionnant normalement ?

Reply

Marsh Posté le 08-10-2007 à 18:46:08    

Voir mon exemple corrigé
 

Code :
  1. $ cat a.cc
  2. #include "a.hh"
  3. namespace A { int x = 42; }
  4. $ cat a.hh
  5. namespace A { extern int x; }
  6. $ cat main.cc
  7. #include "a.hh"
  8. int main() { return A::x; }
  9. $ g++ -Wall main.cc a.cc
  10. $ ./a.out; echo $?
  11. 42

Reply

Marsh Posté le 08-10-2007 à 18:51:06    

OK !!!!!!
 
Merci beaucoup Taz de cet exemple qui fonctionne parfaitement  :) .
 
Il ne me reste plus qu'à analyser tout cela pour comprendre mes problèmes  ;) .
 
Merci également Tuxce du temps passé.
 
Je dormirais mieux ce soir.

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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