Domanda

sto ottenendo questo errore quando si tratta di una serie di classi tra cui un l'altro:

error: expected class-name before '{' token

Vedo quello che sta succedendo, ma non so come correggere correttamente. Qui è una versione astratta del codice:

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;
}

A partire dal main.cpp , è possibile determinare che questo è ciò che il compilatore vede:

#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

A 's definizione non è completa quando si arriva a B . Mi è stato detto che a volte è necessario utilizzare una dichiarazione anticipata e quindi spostare il #include dichiarazione in cpp file, ma non sto avendo alcuna fortuna con quello. Se provo qualcosa di simile, ho semplicemente ottengo l'errore aggiuntivo:

error: forward declaration of 'struct ClassName'

Penso che forse sto solo non fare le cose al posto giusto. Per favore qualcuno può mostrarmi come ottenere questo codice per compilare? Grazie mille!


Edit: Voglio sottolineare che questo è solo astratta versione del codice vero e proprio. Mi rendo conto che non ci sono riferimenti a K in A o B a J , ma ci sono nel reale codice e sento che sono completamente necessari. Forse, se mi danno una breve descrizione delle classi reali, qualcuno può aiutarmi a ristrutturare o risolvere il mio codice.

Class A è una classe nodo astratta che funge da interfaccia per i nodi di un grafo. Class B è uno di quello che sarà un certo numero di diverse implementazioni di A . Nella stessa maniera, classe J è una classe astratta Pro e K è il corrispondente attuazione. Ecco il codice con un po 'più di contesto:

A.h (Abstract 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() {}

B.h (Nodo Concrete)

#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 (Abstract visitatori)

#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 (Calcestruzzo visitatori)

#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;
}

ho dovuto aggiungere alcune dichiarazioni in avanti per fare alcuni altri errori che sembravano (quando ho aggiunto i dettagli) andare via. Alcuni di loro potrebbero non essere necessari o correggere.

È stato utile?

Soluzione

inclusioni circolari non funzionano.

Cercate di mantenere le inclusioni al minimo indispensabile. Se lo fai, potrete sia tutto bene del tutto, o scoprirete problemi nel vostro disegno. Nel tuo caso, non vedo nulla di male con il vostro disegno.

Quando si definisce di classe K, si sta utilizzando solo un puntatore ad un oggetto di tipo B. che non necessita di B da definire (come in "includere il file header"), solo per essere dichiarata (dichiarazione anticipata va bene ). Quindi, nel tuo caso, la rimozione di inclusione di intestazione "B.h" sostituito da "classe B"; è sufficiente. (Lo stesso vale per la classe J)

Altri suggerimenti

I tuoi inclusioni di intestazione sono circolari. A -> K -> J -> B -> A. Utilizzo in avanti dichiarazioni è il modo più semplice per evitare tale complessità, ma è possibile solo quando la classe viene dichiarata solo usa i riferimenti o puntatori alla classe di essere incluso. Non è possibile utilizzare in avanti dichiarazione K.h o B.h, per esempio, perché ereditano rispettivamente J e A. Tuttavia, si può essere in grado di sostituire il #include "K.h" in A.h con class K; a seconda di come in realtà si sta utilizzando K in A.

Parlare di confusione.

In questo esempio concreto, rimuovere il

#include "B.h"

da file J.h poiché Non e' necessario lì. Se questo non funziona, avremmo bisogno di qualche dettaglio in più su come J usa B ...

Modifica

Dal J utilizza solo un puntatore B, il consiglio rimane lo stesso :-):

Rimuovi #include "B.h" da J.h e sostituirlo con una dichiarazione anticipata di B:

(J.h)
class B;

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

Anche rimuovere #include "K.h"from A.h.

Importante

Naturalmente è necessario aggiungere la necessaria include nei rispettivi file CPP:

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

(Lo stesso vale per A.cpp, includere K.h)

Il problema principale è che i file di intestazione includono l'un l'altro in modo circolare. A include K che comprende J che include B che comprende poi una volta ... Non si dovrebbe mai bisogno di una situazione in cui questo accade. Si dovrebbe tornare al tavolo da disegno di progettazione e tagliate alcune delle dipendenze, o riorganizzare le vostre classi del tutto in modo che questa dipendenza circolare non accade.

Il problema è che i file di intestazione ciclicamente dipendono l'uno dall'altro. Non includere K.h in A.h e B.h in J.h. Essi non sono lì necessari.

Per quanto riguarda la tua modifica: questo non è il modo migliore per gli oggetti di interagire. Ripensare il vostro disegno. Chi chiama node.accept(visitor)? Non puoi chiamare direttamente visitor(node)?

Inoltre, se si sta cercando di progettare una biblioteca grafico, dare un'occhiata a Boost.Graph biblioteca.

Detto questo, dal momento che si usa solo un puntatore a B in J.h, non è necessario includere B.h, solo in avanti, dichiarare la classe.

class B;

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

quindi includere B.h nel file K.cpp.

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

void K::visit(const B* b) const
{
    // use b here any way you want
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top