2009-04-12 9 views
1

J'obtiens cette erreur en traitant avec un certain nombre de classes dont l'autre:Tricky classe Héritage C de Définition du problème

error: expected class-name before '{' token 

Je vois ce qui se passe, mais je ne sais pas comment corriger correctement, il . Voici une version abstraite du code:

A.h

#ifndef A_H_ 
#define A_H_ 

#include "K.h" 

class A 
{ 
    public: 
     A(); 

}; 

#endif /*A_H_*/ 

A.cpp

#include "A.h" 

A::A() {} 

B.h

#ifndef B_H_ 
#define B_H_ 

#include "A.h" 

class B : public A 
{ // error: expected class-name before '{' token 
    public: 
     B(); 
}; 

#endif /*B_H_*/ 

B.cpp

#include "B.h" 

B::B() : A() {} 

J.h

#ifndef J_H_ 
#define J_H_ 

#include "B.h" 

class J 
{ 
    public: 
     J(); 
}; 

#endif /*J_H_*/ 

J.cpp

#include "J.h" 

J::J() {} 

K.h

#ifndef K_H_ 
#define K_H_ 

#include "J.h" 

class K : public J 
{ // error: expected class-name before '{' token 
    public: 
     K(); 
}; 

#endif /*K_H_*/ 

K.cpp

#include "K.h" 

K::K() : J() {} 

main.cpp

#include "A.h" 

int main() 
{ 
    return 0; 
} 

À partir de main.cpp, je peux déterminer que c'est ce que voit le compilateur :

#include "A.h" 

#ifndef A_H_ 
#define A_H_ 

#include "K.h" 

#ifndef K_H_ 
#define K_H_ 

#include "J.h" 

#ifndef J_H_ 
#define J_H_ 

#include "B.h" 

#ifndef B_H_ 
#define B_H_ 

#include "A.h" 

class B : public A 
{ // error: expected class-name before '{' token 

Ainsi, Une définition de est pas terminée quand nous arriverons à B. On m'a dit que parfois vous devez utiliser une déclaration avant et ensuite déplacer l'instruction #include dans le fichier .cpp, mais je n'ai pas de chance avec ça. Si je tente quelque chose comme ça, je reçois simplement l'erreur supplémentaire:

error: forward declaration of 'struct ClassName' 

Je pense que peut-être je ne suis pas faire les choses dans les bons endroits. Quelqu'un peut-il me montrer comment compiler ce code? Merci beaucoup!


Modifier: Je tiens à souligner que c'est juste une version abstraite du code réel.Je me rends compte qu'il n'y a pas de références à K dans A ou B dans J, mais il y a dans le code réel et je pense qu'ils sont tout à fait nécessaire. Peut-être que si je donne une brève description des vraies classes, quelqu'un peut m'aider à restructurer ou réparer mon code.

Classe est une classe de noeuds abstraite qui agit comme une interface pour les noeuds dans un graphique. Classe B est l'un de ce qui sera un certain nombre de différentes implémentations de A. De la même manière, la classe J est une classe Visiteur abstraite et K est l'implémentation correspondante. Voici le code avec un peu plus de contexte:

Ah (Résumé Node)

#ifndef A_H_ 
#define A_H_ 

#include "K.h" 

class K; 

class A 
{ 
    public: 
     A(); 

     virtual void accept(const K&) const = 0; 
}; 

#endif /*A_H_*/ 

A.cpp

#include "A.h" 

A::A() {} 

Bh (Noeud béton)

#ifndef B_H_ 
#define B_H_ 

#include "A.h" 

class K; 

class B : public A 
{ // error: expected class-name before '{' token 
    public: 
     B(); 

     virtual void accept(const K&) const; 
}; 

#endif /*B_H_*/ 

B.cpp

#include "B.h" 

B::B() : A() {} 

void B::accept(const K& k) const { k.visit(this); } 

J.h (Résumé Visiteur)

#ifndef J_H_ 
#define J_H_ 

#include "B.h" 

class B; 

class J 
{ 
    public: 
     J(); 

     virtual void visit(const B*) const = 0; 
}; 

#endif /*J_H_*/ 

J.cpp

#include "J.h" 

J::J() {} 

K.h (visiteur en béton)

#ifndef K_H_ 
#define K_H_ 

#include "J.h" 

class B; 

class K : public J 
{ // error: expected class-name before '{' token 
    public: 
     K(); 

     virtual void visit(const B*) const; 
}; 

#endif /*K_H_*/ 

K.cpp

#include "K.h" 

K::K() : J() {} 

void K::visit(const B*) const {}; 

main.cpp

#include "A.h" 

int main() 
{ 
    return 0; 
} 

je devais ajouter quelques déclarations avant de faire quelques erreurs supplémentaires qui sont apparues (quand j'ajouté en détail) allez-vous en. Certains d'entre eux peuvent ne pas être nécessaires ou corrects.

Répondre

1

Les inclusions circulaires ne fonctionnent pas. Essayez de limiter au maximum les inclusions. Si vous faites cela, tout ira bien, ou vous découvrirez des problèmes dans votre conception. Dans votre cas, je ne vois rien de mal avec votre conception.Lorsque vous définissez la classe K, vous utilisez uniquement un pointeur vers un objet de type B. Cela ne nécessite pas de définir B (comme dans "include the header file"), mais seulement d'être déclaré (la déclaration forward est bien). Donc, dans votre cas, suppression de l'inclusion à l'en-tête "B.h" remplacé par "classe B"; est suffisant. (il en va de même pour la classe J)

6

Vos inclusions d'en-tête sont circulaires. A -> K -> J -> B -> A. L'utilisation de déclarations directes est le moyen le plus simple d'éviter une telle complexité, mais cela n'est possible que lorsque la classe déclarée utilise uniquement des références ou des pointeurs vers la classe incluse. Vous ne pouvez pas utiliser la déclaration forward dans K.h ou B.h, par exemple, car ils héritent de J et de A respectivement. Toutefois, vous pouvez remplacer le #include "K.h" dans A.h avec class K; en fonction de la façon dont vous utilisez effectivement K dans A.

Parlez de confusion.

+0

J'ai essayé ceci et j'ai obtenu l'erreur "déclaration de 'struct K'". J'ai ajouté plus de détails à ma question, alors j'espère que vous pourrez le réévaluer. – Scott

+0

Je remarque que dans votre premier exemple vous avez le #include "K.h" et la classe K; ligne. Avez-vous essayé de supprimer la ligne #include ou est-ce juste un oubli dans votre message? –

+0

Je ne comprends pas. Dans mon premier exemple? J'inclus K dans la classe A, mais il n'y a pas de déclaration forward. J'ai essayé de supprimer le "#include" et d'ajouter une déclaration avant comme vous l'avez dit, mais comme je l'ai dit, j'ai eu l'erreur: "déclaration avant de 'struct K'." – Scott

2

Le problème est que vos fichiers d'en-tête dépendent cycliquement l'un de l'autre. N'incluez pas K.h dans A.h et B.h dans J.h. Ils ne sont pas nécessaires là-bas.

En ce qui concerne votre modification: ce n'est pas la meilleure façon d'interagir avec vos objets. Repensez votre conception. Qui appelle node.accept(visitor)? Tu ne peux pas appeler directement le visitor(node)?

De plus, si vous essayez de créer une bibliothèque de graphes, jetez un oeil à la bibliothèque Boost.Graph. Cela dit, puisque vous n'utilisez qu'un pointeur vers B dans J.h, vous n'avez pas besoin d'inclure B.h, déclarez simplement la classe à l'avance.

class B; 

struct J 
{ 
    virtual void visit(const B*) const = 0; 
}; 

ensuite inclure B.h dans votre fichier K.cpp.

#include "K.h" 
#include "B.h" 

void K::visit(const B* b) const 
{ 
    // use b here any way you want 
} 
+0

Je suis désolé si mon exemple était trompeur, mais dans la version réelle du code, les inclusions sont nécessaires. J'ai édité ma question, alors peut-être pourriez-vous y jeter un autre coup d'oeil. – Scott

3

Dans cet exemple concret, retirez le

#include "B.h" 

du fichier J.h car il est pas nécessaire là. Si cela ne fonctionne pas, nous aurions besoin de quelques détails sur la façon dont J utilise B ...

EDIT

Depuis J utilise seulement un pointeur vers B, les conseils reste le même :-):

Supprimer #include "B.h" de J.h et de le remplacer par une déclaration avant de B:

(J.h) 
class B; 

class J 
{ 
    // ... 
    virtual void visit(const B*) const = 0; // This will work with forward declaration 
} 

Supprimez également #include "K.h" de A.h.

IMPORTANT

Bien sûr, vous devez ajouter le nécessaire inclut dans les fichiers du RPC respectifs:

(J.cpp) 
#include "B.h" 
// ... 
// Go ahead with implementation of J 
// ... 

(Idem pour A.cpp, inclure K.h)

+0

J'ai ajouté un peu de contexte à ma question. J'espère que ça aide à expliquer ce que j'essaie de faire. – Scott

2

Le principal problème est que vos fichiers d'en-tête se comprennent de manière circulaire. A inclut K qui inclut J qui inclut B qui inclut A à nouveau ... Vous ne devriez jamais avoir besoin d'une situation où cela se produit. Vous devriez revenir à la planche à dessin de conception et soit couper certaines des dépendances, soit réorganiser entièrement vos classes afin que cette dépendance circulaire ne se produise pas.

+0

Pouvez-vous s'il vous plaît jeter un oeil à ma question mise à jour? J'ai ajouté d'autres détails, alors peut-être pourriez-vous m'aider à restructurer le code d'une manière ou d'une autre. – Scott

Questions connexes