2010-03-30 6 views
4

Quel est le problème avec ce code? Nous avons ici deux fichiers: classA.h et classB.hInstances de classe mutuelle en C++

classA.h:

#ifndef _class_a_h_ 
#define _class_a_h_ 

#include "classB.h" 

class B; //???? 

class A 
{ 
public: 
    A() { 
     ptr_b = new B(); //???? 
    } 

    virtual ~A() { 
     if(ptr_b) delete ptr_b; //???? 
        num_a = 0; 
    } 

    int num_a; 
    B* ptr_b; //???? 
}; 

#endif //_class_a_h_ 

classB.h:

#ifndef _class_b_h_ 
#define _class_b_h_ 

#include "classA.h" 

class A; //???? 

class B 
{ 
public:  
    B() { 
     ptr_a = new A(); //???? 
        num_b = 0; 
    } 

    virtual ~B() { 
     if(ptr_a) delete ptr_a; //???? 
    } 

    int num_b; 
    A* ptr_a; //???? 
}; 

#endif //_class_b_h_ 

lorsque je tente de compiler , le compilateur (g ++) dit:

classB.h: In constructor ‘B::B()’:

classB.h:12: error: invalid use of incomplete type ‘struct A’

classB.h:6: error: forward declaration of ‘struct A’

classB.h: In destructor ‘virtual B::~B()’:

classB.h:16: warning: possible problem detected in invocation of delete operator:

classB.h:16: warning: invalid use of incomplete type ‘struct A’

classB.h:6: warning: forward declaration of ‘struct A’

classB.h:16: note: neither the destructor nor the class-specific operator delete will be

called, even if they are declared when the class is defined.

+2

Chaque fois que des classes sont couplées, votre conception doit probablement être refactorisée. – GManNickG

+0

@GMan: À la seule exception de l'implémentation du modèle d'itérateur, beaucoup d'accord. +1 –

Répondre

9

Vous ne pouvez pas créer des instances d'un type incomplet (le compilateur ne sait rien à propos de la classe!)

Vous devez déplacer les définitions de vos fonctions (le constructeur de A et B) dans un fichier C++ qui peut inclure les deux en-têtes (ou dans plusieurs fichiers C++, si vous suivez la convention selon laquelle vous avez une classe par fichier). Cela étant dit, votre code comme écrit a un sérieux problème: chaque A crée une instance de B et chaque B crée et instance de A. Vous vous retrouverez avec une récursion infinie et vous finirez par manquer de mémoire . Deux punaises mineures: vous n'avez pas besoin de tester si un pointeur est nul avant d'appeler supprimer (il est sûr de supprimer un pointeur nul), et vous devez changer vos gardes d'inclusion (les noms commençant par un trait de soulignement dans l'espace de noms global est réservé à l'implémentation).

+1

+1 pour la récursivité – Rado

2

EDIT: Lire James McNellis répondre d'abord - c'est un exemple de code de ce que vous auriez à faire. Mais la récursion est le plus gros point et il mérite des upvotes pour ce point particulier - pas moi :)

Vous ne pouvez pas utiliser les fonctions en ligne ici comme la définition complète pour les classes A et B n'est pas disponible lorsque vous êtes les déclarant en ligne. Déclarez-les comme des fonctions normales et vous n'aurez aucun problème avec les déclarations avancées que vous avez.

classA.h

#ifndef _class_a_h_ 
#define _class_a_h_ 

#include "classB.h" 

class B; //???? 

class A 
{ 
public: 
    A(); 
    virtual ~A(); 
    int num_a; 
    B* ptr_b; 
}; 

#endif //_class_a_h_ 

classB.h

#ifndef _class_b_h_ 
#define _class_b_h_ 

#include "classA.h" 

class B 
{ 
public:  
    B(); 
    virtual ~B(); 
    int num_b; 
    A* ptr_a; 
}; 

#endif //_class_b_h_ 

classes.cpp

#include "classA.h" 
#include "classB.h" 

A::A() { 
    ptr_b = new B(); //???? 
} 

A::~A() { 
    if(ptr_b) delete ptr_b; //???? 
} 

B::B() { 
    ptr_a = new A; //???? 
} 

B::~B() { 
    if(ptr_a) delete ptr_a; //???? 
} 
+0

Mais ... attention à la récursivité infinie! –

+0

@Drew Hall: Bon point - n'a pas pensé à ça. Mais ne va pas voler les points de James McNellis ici - il les mérite. –

+0

Je pense que ça ne marche pas du tout. avez-vous essayé de le compiler vous-même? – sepisoad

1

classB.h: In constructor ‘B::B()’:

classB.h:12: error: invalid use of incomplete type ‘struct A’

A n'est pas entièrement défini. Vous lui avez seulement donné un prototype (class A;).

classB.h:6: error: forward declaration of ‘struct A’

classB.h: In destructor ‘virtual B::~B()’:

Je pense c'est le même problème. Il doit savoir comment A est défini afin qu'il sache combien de mémoire libérer. Refaire votre code pour supprimer la dépendance circulaire. (A crée B, et B crée A ... crée B, crée A, crée B ...)

0

La solution simple consiste à extraire les définitions de fonctions de vos membres dans les fichiers classA.cpp et classB.cpp.Supprimez les inclusions mutuelles des fichiers d'en-tête et insérez-les à la place dans les fichiers .cpp.

Partout où la classe A ou B est utilisée plus que simplement dans le nom (autrement dit, il suffit de nommer son type de pointeur ou de référence), une déclaration de classe complète doit déjà être présente. Avec votre design include/inline actuel, l'un ou l'autre ne sera pas forcément complet. En divisant les implémentations de classe en fichiers .cpp, vous autorisez les déclarations à s'exécuter avant d'instancier des objets de type A ou B.

Questions connexes