2010-09-10 7 views
5

Comment résolvez-vous créé en incluant un fichier d'en-tête du même nom qu'un autre fichier d'en-tête déjà indirectement inclus à la suite d'un autre include?C++: inclure plusieurs fichiers d'en-tête ayant le même nom d'espaces de noms différents

Par exemple:

// src/blah/a.hpp 
#ifndef A_HPP 
#define A_HPP 

namspace blah 
{ 

class A 
{ 
} 

} 

#endif 

// src/blah/b.hpp 
#ifndef B_HPP 
#define B_HPP 

#includes "a.hpp" 

namspace blah 
{ 

class B 
{ 
} 

} 

#endif 

// src/foo/a.hpp 
#ifndef A_HPP 
#define A_HPP 

namspace foo 
{ 

class A 
{ 
} 

} 

#endif 

// src/foo/c.hpp 
#ifndef C_HPP 
#define C_HPP 

#includes "../b.hpp" 
#includes "a.hpp"  // won't be included due to multiple inclusion prevention 

namspace foo 
{ 

class C 
{ 
} 

} 

#endif 

Dans le dernier fichier d'en-tête, a.hpp ne seront pas inclus en raison des multiples agents de préprocesseur d'inclusion. Vraiment, cela devrait être correct mais puisque les classes sont dans des espaces de noms différents. Je me rends compte que le moyen le plus simple est de simplement changer le nom de foo/a.hpp ou juste de lui donner un faux nom dans la garde d'inclusion multiple. Y a-t-il un meilleur moyen?

EDIT Je comprends que vous pouvez résoudre ce problème en utilisant un nom plus descriptif dans les directives #define et #ifndef (par exemple FOO_A_HPP et BLAH_A_HPP), mais je veux savoir si cela est la meilleure façon recommandée ou . Est-ce que certaines personnes recommandent d'utiliser un nom de fichier différent comme meilleure solution ou n'est-ce pas important? Recommanderiez-vous en utilisant la convention:

<NAMESPACE>_<CLASS>_HPP 

au lieu de

<CLASS>_HPP 

pour donner une meilleure chance d'éviter ces problèmes en général?

+0

Pourquoi est-ce marqué C? –

+0

Je place toujours l'espace de noms dans mes gardes. Les outils automatisés mettront un GUID comme garde d'en-tête. L'essentiel est qu'ils DOIVENT être uniques (pas seulement dans votre projet, mais de préférence unique dans tous les fichiers du monde dans toutes les dimensions si possible). –

Répondre

7

vous résolvez cela, simplement, ne pas utiliser le même #define au sommet ...

Il serait préférable d'utiliser BLAH_A_HPP et FOO_A_HPP etc afin que le #define comprend également le nom d'espace de noms.

Edit: Eh bien, je recommande de faire ce qui suit:

1) Ne nommez pas les mêmes en-têtes (c.-à-utiliser un autre nom de fichier ... cela ne suffit pas toujours) et utiliser des noms différents #define.
2) Ne nommez pas les classes de la même façon. Mettez 1 classe par en-tête et nommez l'en-tête après la classe
3) Si elles sont différenciées par un espace de noms, utilisez cet espace de noms dans le nom de fichier ET #define
4) Ajoutez un ID #define qui vous est propre (Je pourrais utiliser GOZ par exemple)
5) Utiliser #pragma une fois. C'est utile pour les compilateurs qui l'utilisent.

C'est une question de goût. Choisissez un système qui fonctionne pour vous et respectez-le. Il n'y a pas de vrai ou de faux. Tant que cela fonctionne et est cohérent.

+0

compris, voir mon édition pour plus de précisions sur la question. Recommanderiez-vous la convention de NAMESPACE_CLASS_HPP en général? Est-ce mieux que de simplement changer le nom de fichier ou n'est-ce pas important? – deuberger

+0

@deuberger: changer le nom de fichier ne fera aucune différence; le problème est dû au nom de garde include dupliqué. Et oui, je recommanderais d'utiliser quelque chose comme NAMESPACE_CLASS_HPP pour le garde d'inclusion. –

+0

Vrai c'est une "solution partielle" ... Je vais le réparer :) – Goz

0

Bien qu'il n'y ait pas d'espaces de noms dans C, je pense que cela fonctionne à la fois pour C et C++.

#ifndef BLAH_B_HPP 

et

#ifndef FOO_B_HPP 
1

Lorsque MSVC crée une classe, il ajoutera un GUID à votre nom de garde pour éviter ce genre de problème.

+0

Rien ici ne dit qu'il utilise MSVC, ce qui n'est pas possible depuis son C++. – alternative

+0

@mathepic: qu'est-ce que tu veux dire c'est pas possible puisque c'est du C++, c'est quoi ce non-sens? Donner un exemple de manière standard pour s'assurer que les protecteurs d'en-tête sont uniques avec un arrière-plan dans lequel l'idée est venue, ne pas dire que l'utilisation de MSVC est nécessaire. –

+0

@mathepic: Non, ça inclut certainement le C++, et c'est encore le point. –

0

Comme vous l'avez suggéré vous-même, la manière normale de procéder consiste à rendre vos identifiants de garde uniques, en ajoutant un GUID, un chemin complet ou autre.

Dans VC++ il y a aussi un pragma pour prendre soin d'inclusion multiples pour vous, afin que vous n'avez pas besoin d'écrire le #if defined(HUMPTYDUMPTY) vous bit, il va comme

#pragma once 

a été autour pendant quelques itérations VC++ maintenant, mais pour les autres compilateurs, vous devez vérifier. Cela vous évite également de chercher des noms uniques.

Édité: Juste jeté un coup d'oeil et l'Internet pense que c'est aussi dans GCC. On dirait que les gardes de style #include sont très 20ème siècle ...

+0

Bon point, bien qu'il semble que #pragma en général et #pragma une fois n'est pas la méthode préférée. Voir: http://stackoverflow.com/questions/787533/is-pragma-once-a-safe-include-guard. – deuberger

+0

Il suffit de lire le post sur le pragma. Je ne suis pas vraiment inquiet de la performance ici; Je pense simplement que plus vous devez taper, plus vous risquez de commettre des erreurs. Si vous faites beaucoup de portage de code entre des compilateurs incompatibles, cela peut poser problème. Quoi qu'il en soit, je n'aurais rien perdu de mon sommeil. –

2

Je suis surpris que personne ne mentionne la solution simple d'utilisation #undef A_HPP comme ci-dessous

//src/foo/c.hpp 
#ifndef C_HPP 
#define C_HPP 

#includes "../b.hpp" 
#undef A_HPP 
#includes "a.hpp" 
... 

Ceci est particulièrement bon si foo/c.hpp est le seul fichier que l'on peut ou est autorisé à changer.

+0

Bon point et je suis surpris maintenant que vous le mentionnez. – deuberger

Questions connexes