2011-07-22 10 views
5

Eventuali duplicati:
Proper way to #include when there is a circular dependency?L'inclusione reciproca in C++ .. come funziona?

Sono abbastanza nuovo per C++ ed avere la domanda posta nel titolo. O più precisamente: se A.h include B.h e B.h include A.h, ricevo un messaggio di errore perché "include # file" C: ... \ A.h "include se stesso". File: B.h

Non sono riuscito a trovare un modo per aggirare questo problema, e la mia configurazione generale richiede praticamente la relazione tra queste classi. Qualche possibilità di farlo funzionare?

+0

Buona domanda. I preprocessori funzionano riga per riga, si studierà come '# ifdef',' # define' e '# endif' funzionano :-) – Stan

risposta

6

Semplice: non lasciare che A.h includa B.h. E viceversa.

In generale, i file di intestazione dovrebbero includere il minimo assolutamente possibile. È possibile utilizzare la dichiarazione di inoltro per aggirare un sacco di inclusioni. L'unica volta che devi assolutamente includere qualcosa in un'intestazione è se ci sono oggetti che vengono usati come non riferimento in quell'intestazione.

Quindi evitate di farlo. Usa Pimpl per evitare di inserire i membri della classe nelle intestazioni. E a meno che non si tratti di un codice di modello o del supporto inlining, non scrivere il codice effettivo nelle intestazioni.

Il caso peggiore è che sarà necessario creare un C.h che definisca ciò di cui hanno bisogno A.h e B.h.

+1

TIL: Forward delcaration =) – ArniBoy

+0

Grazie a @Nicol, questo è un buon punto. In generale (non in questo caso specifico di doppia inclusione), puoi spiegare perché preferiresti una dichiarazione anticipata ad una inclusione normale? – Enzo

7

Utilizzare Includi guardie nei file di intestazione. http://en.wikipedia.org/wiki/Include_guard

#ifndef MYHEADER_H 
#define MYHEADER_H 

//add decls here 

#endif 

In questo modo se i file di intestazione sono compresi più di una volta il compilatore li ignora.

Inoltre, come regola generale, se si include B.h che ha A.h, sarebbe meglio includere A.h e B.h nell'applicazione anziché fare affidamento sull'inclusione di B.h.

Inoltre inserisce solo dichiarazioni nel file di intestazione.

Evita definizioni a tutti i costi nei file di intestazione.

0

provare ad aggiungere guardie di intestazione,

#ifndef _A_H_ 
#define _A_H_ 
... 
.. 
. 
#endif /* #ifndef _A_H_ */ 

Non si dovrebbe mai includere un file di intestazione per due volte, si traduce in ridefinizione ..

0

Quando un file di intestazione viene aggiunto a un file che viene incluso durante la parte pre-elaborazione di compilazione. Quindi includendo B.h in A.h. E includendo A.h in B.h. È una specie di infinitamente ricorsivo e il file viene incluso più volte.

Compreso B.h in A.h ammonta a A.h < - B.h Compreso A.h in B.h ammonta a Bh < - A.h

Così il suo re del ciclo ricorsivo infinito.

1

Non hai detto quali sono queste reciproche dipendenze, quindi queste sono solo supposizioni. In tutti questi presuppongo che A.h definisca class A e B.h definito class B.

Caso 1: La dipendenza reciproca avviene tramite puntatori o riferimenti.
Ad esempio, class A contiene un membro dati di tipo B* e viceversa. In questo caso, nessuna intestazione deve corrispondere a #include l'altra. Utilizzare invece una dichiarazione diretta.

Caso 2: La dipendenza reciproca avviene tramite oggetti.
Ad esempio, class A contiene un membro dati di tipo B e viceversa. In questo caso tu sei protetto.

Caso 3: dipendenze miste.
Ad esempio, class A contiene un membro dati di tipo B ma class B contiene un membro dati di tipo A*. Ora A.h ha bisogno di #include B.h, ma B.h ha semplicemente bisogno di una dichiarazione anticipata di class A.

È consigliabile utilizzare sempre una sorta di protezione da inclusione una tantum per impedire l'inclusione di un'intestazione più volte.

1

Partendo dal presupposto che in ogni intestazione di avere una classe, si può fare in questo modo:

File di intestazione: "Ah"

#ifndef A_H 
#define A_H 
Class B; 

Class A { 
public: 
    B name_of_B_; 
} 

#endif 

Con #ifndef A_H #define A_H #endif a garantire che ogni intestazione è incluso solo una volta . Dovresti usarlo praticamente in tutti i file di intestazione che produci, non solo in questo caso speciale di doppia inclusione. Con Class B; si dichiara che verrà definita una classe denominata "B".

Class B { 
public: 
    A name_of_A_; 
} 

#endif 

Stessa storia della classe "B". In questo modo eviti l'inclusione del ciclo infinito.

+1

Il presente include alla fine di ogni file di intestazione è completamente inutile. Dichiarazione in avanti come la Classe A; è un meccanismo per dire al compilatore che una classe A sarà presente più tardi, lo stesso per la Classe B. A questo punto, non importa quando verrà risolta una delle due classi A o B, perché hai appena detto al compilatore che loro saranno entrambi lì alla fine della compilazione usando la dichiarazione forward. Pertanto, gli include alla fine del file di intestazione possono essere rimossi perché non servono a nulla. Saluti;) – ForceMagic

+0

Giusto! Grazie per segnalarlo. – Enzo