Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Question sans doute posée mille fois !!!

8 réponses
Avatar
WebShaker
J'ai un petit problème que je n'arrive pas a résoudre.

j'ai une class A qui contient un tableau de d'objet de la classe B.

D'un autre coté j'aimerai pouvoir stocker un pointeur de la class A dans
l'objet B !!!

mais je ne peux pas inclure classA.h dans la définition de l'objet B
et inclure classB.h dans la définition de l'objet A

car évidement, l'un des deux fichiers est forcément parsé en premier !!!

Comment solutionne t-on ce problème?

Merci
Etienne

8 réponses

Avatar
JKB
Le Sun, 13 Feb 2011 10:29:59 +0100,
WebShaker écrivait :
J'ai un petit problème que je n'arrive pas a résoudre.

j'ai une class A qui contient un tableau de d'objet de la classe B.

D'un autre coté j'aimerai pouvoir stocker un pointeur de la class A dans
l'objet B !!!

mais je ne peux pas inclure classA.h dans la définition de l'objet B
et inclure classB.h dans la définition de l'objet A

car évidement, l'un des deux fichiers est forcément parsé en premier !!!

Comment solutionne t-on ce problème?



Bonjour,

Si j'ai bien compris le problème, avec quelque chose du genre :

#ifdef _INCLUDE1_HPP_
# define _INCLUDE1_HPP_

// include_1.hpp
#endif

dans le fichier d'en-tête.

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
Alain Ketterlin
WebShaker writes:

j'ai une class A qui contient un tableau de d'objet de la classe B.

D'un autre coté j'aimerai pouvoir stocker un pointeur de la class A
dans l'objet B !!!



----- B.hpp ----
class A;
class B {

A * a; ...

};
----- A.hpp ----
#include "B.hpp"
class A {

B bs[...]; ...

};
----------------

Plus les gardes #ifndef/... habituelles.

-- Alain.
Avatar
Etienne Rousee
Le 13/02/2011 10:29, WebShaker a écrit :
j'ai une class A qui contient un tableau de d'objet de la classe B.

D'un autre coté j'aimerai pouvoir stocker un pointeur de la class A dans
l'objet B !!!

mais je ne peux pas inclure classA.h dans la définition de l'objet B
et inclure classB.h dans la définition de l'objet A

car évidement, l'un des deux fichiers est forcément parsé en premier !!!

Comment solutionne t-on ce problème?



Dans classA.h :

class A; // prototypes de classes
class B;

classA
{
...........
B _tabB[10]; // par exemple, ou: B *_tabB;
};

Dans classB.h :

class A; // prototypes de classes
class B;

classB
{
...........
A *_ptrA;
};

Et il faut inclure classB.h avant classA.h.

Mais, plutôt qu'un tableau de B, je mettrais
un vector de B* dans la classe A:
std::vector<B *> _vecB;
Comme ça l'ordre des inclusions serait indifférent.

--

Etienne
Avatar
Mickaël Wolff
Tout d'abord, le sujet n'est absoluement pas en charte. Il faut un
titre plus explicite.

On 13/02/11 09:51, Etienne Rousee wrote:
Dans classA.h :

class A; // prototypes de classes


En réalité, c'est une déclaration.
Au fait, on appelle cette technique « forwarding declaration ».

Dans classB.h :

class A; // prototypes de classes
class B;


Déclarer class B est inutile ici.

classB
{
...........
A *_ptrA;


Les noms de symboles commençant par un underscore sont réservés aux
implémenteurs de la STL. Le comportement ici est donc indéfini.


Et il faut inclure classB.h avant classA.h.


Pourquoi ? Il faut inclure le moins de fichiers possible dans les
en-têtes, pour limiter le couplage. À moins que tu ne parlais de
l'inclusion des en-têtes dans le module de définition de la class B ?

Mais, plutôt qu'un tableau de B, je mettrais
un vector de B* dans la classe A:
std::vector<B *> _vecB;
Comme ça l'ordre des inclusions serait indifférent.


Au delà de l'ordre des includes, c'est surtout qu'un std::vector sera
plus naturel en C++ qu'un tableau à la C.
Avatar
Michael Doubez
On 13 fév, 18:11, Mickaël Wolff wrote:
   Tout d'abord, le sujet n'est absoluement pas en charte. Il faut un
titre plus explicite.

On 13/02/11 09:51, Etienne Rousee wrote:> Dans classA.h :

> class A; // prototypes de classes

   En r alit , c'est une d claration.
   Au fait, on appelle cette technique forwarding declaration .

> Dans classB.h :

> class A; // prototypes de classes
> class B;

   D clarer class B est inutile ici.

> classB
> {
> ...........
> A *_ptrA;

   Les noms de symboles commen ant par un underscore sont r serv s au x
impl menteurs de la STL. Le comportement ici est donc ind fini.



Uniquement dans le namespace global.

Les noms réservés dans tous les namespaces sont ceux commençant par u n
underscore ouis une majuscule ou les noms ayant un double underscore.

[snip]

--
Michael
Avatar
Mickaël Wolff
On 13/02/11 18:43, Michael Doubez wrote:

Uniquement dans le namespace global.

Les noms réservés dans tous les namespaces sont ceux commençant par un
underscore ouis une majuscule ou les noms ayant un double underscore.



Merci pour la précision. J'avais banni l'usage du leading underscore
depuis que j'avais appris que c'était réservé dans certains cas. Ceci
dit, ça m'explique pourquoi ils utilisent _M_.* dans la STL fournie avec
GCC.

Ceci dit, je pense que c'est quand même une bonne idée de ne pas
utiliser tout les symboles commençant par underscore. Vu que c'est
réservé dans une portée suppérieure, on peut éventuellement avoir des
problèmes de symbole caché.
Avatar
Etienne Rousee
Le 13/02/2011 18:11, Mickaël Wolff a écrit :
> Tout d'abord, le sujet n'est absoluement pas en charte. Il faut un
> titre plus explicite.


Oui, j'ai gardé le titre de l'OP, comme toi.

> On 13/02/11 09:51, Etienne Rousee wrote:
>> Dans classA.h :
>>
>> class A; // prototypes de classes


> En réalité, c'est une déclaration.
> Au fait, on appelle cette technique « forwarding declaration ».



Et en français ? Dans l'esprit, c'est prévenir le compilateur que ce
nom existe et que c'est un nom de classe.

>> Dans classB.h :
>>
>> class A; // prototypes de classes
>> class B;


> Déclarer class B est inutile ici.
>
>> classB
>> {
>> ...........
>> A *_ptrA;


> Les noms de symboles commençant par un underscore sont réservés aux
> implémenteurs de la STL. Le comportement ici est donc indéfini.


Il n'y a pas de loi là dessus. C'est juste une question de convention
d'écriture. Il se trouve que j'ai appris le C++ avec cette convention,
mais il y en a d'autres. Il doit même y en avoir une par entreprise
ou presque.

>
>> Et il faut inclure classB.h avant classA.h.


> Pourquoi ? Il faut inclure le moins de fichiers possible dans les
> en-têtes, pour limiter le couplage. À moins que tu ne parlais de
> l'inclusion des en-têtes dans le module de définition de la class B ?


Ici, c'est forcément couplé, puisque l'OP veut se servir de A dans B
et de B dans A. Mais effectivement, je parlais de l'inclusion dans
classB.cpp.

>> Mais, plutôt qu'un tableau de B, je mettrais
>> un vector de B* dans la classe A:
>> std::vector<B *> _vecB;
>> Comme ça l'ordre des inclusions serait indifférent.


> Au delà de l'ordre des includes, c'est surtout qu'un std::vector sera
> plus naturel en C++ qu'un tableau à la C.


Oui pour le vecteur, mais B* au lieu de B influe sur l'ordre.

-- Etienne
Avatar
Michael Doubez
On 13 fév, 20:11, Mickaël Wolff wrote:
On 13/02/11 18:43, Michael Doubez wrote:

> Uniquement dans le namespace global.

> Les noms r serv s dans tous les namespaces sont ceux commen ant par un
> underscore ouis une majuscule ou les noms ayant un double underscore.

   Merci pour la pr cision. J'avais banni l'usage du leading undersco re
depuis que j'avais appris que c' tait r serv dans certains cas. Ceci
dit, a m'explique pourquoi ils utilisent _M_.* dans la STL fournie avec
GCC.



Il me semble qu'il y a des cas où ça pourrait poser problème avec le
C99 qui réserve plus de noms; je suppose que c'est dû à l'absence de
namespace. Je crois que POSIX ajoute aussi sont lot de formes
réservées.

En pratique, j'ai jamais vu ni entendu parler de problèmes lié à ça .
Et c'est à mon avis une réserve pour pouvoir ajouter des noms
réservés. Et si quelqu'un râle, qu'on puisse lui dire qu'il n'avait
qu'à ne pas utiliser une forme réservée.


   Ceci dit, je pense que c'est quand m me une bonne id e de ne pas
utiliser tout les symboles commen ant par underscore. Vu que c'est
r serv dans une port e supp rieure, on peut ventuellement avoir des
probl mes de symbole cach .



Dans le contexte d'une fonction membre, je ne vois pas de cas
problème. Peut être dans un cas de classe template où un two-phase
lookup aurait dû être utiliser (i.e. utiliser this->_member) et que la
variable globale est utilisé en lieu et place de la variable membre.
C'est un risque assez vague.

AMA c'est plutôt une question de lisibilité. J'ai utilisé un temps la
notation membre_; mais c'est vraiment laid (membre_->foo() ) et pas
très lisible. J'ai vu certains utiliser m_member , mMember ou
myMember. Le dernière forme étant peut être la plus explicite mais à
un je ne sais quoi qui me déplait (peut être mon orgueil qui refuse
d'utiliser des conventions d'amateur même si des gens aussi
expérimentés que James Kanze l'utilisent :)

Au travaille, nous utilisons tous la forme _member. Et je pense que je
ne m'avance pas trop en disant que c'est la forme la plus populaire.

En fait, pour être tout à fait sûr il faudrait que le langage c++
standardise des namespaces de contexte comme dans certains langages
dynamiques:
- m::* pour désigner les noms membres
- g::* les globales
- a::* pour les arguments de fonction

Comme ça je pourrais écrite

int foo;

class MyClass
{
int foo;
}

void
myClass::myClass(int foo, double bar)
{
m::foo = a::foo;
if( g::foo < m::foo )
{

}
}

Je pense que se réserver des namespaces d'une seule lettre ne
casserait pas beaucoup de code. Et ça serait optionnel.

--
Michael