2011-07-22 13 views
5

Powiel możliwe:
Proper way to #include when there is a circular dependency?Wzajemne uwzględnianie w C++. Jak to działa?

Jestem całkiem nowy, C++ i mają pytanie zadane w tytule. Lub dokładniej: jeśli A.h zawiera B.h i B.h zawiera A.h, pojawia się komunikat o błędzie, ponieważ "include # file" C: ... \ A.h "obejmuje samą siebie". Plik: B.h

Nie mogłem znaleźć sposobu na obejście tego, a moja ogólna konfiguracja prawie wymaga relacji między tymi klasami. Czy istnieje możliwość, aby to zadziałało?

+0

Dobre pytanie. Preprocesory pracują linia po linii, można się nauczyć, jak działają '# ifdef',' # define' i '# endif' :-) – Stan

Odpowiedz

6

Prosta: nie pozwól A.h dołączyć B.h. I wzajemnie.

Ogólnie pliki nagłówkowe powinny zawierać tak mało, jak to tylko możliwe. Możesz użyć deklaracji forward, aby ominąć wiele załączników. Jedynym momentem, w którym absolutnie musisz zawrzeć coś w nagłówku, jest sytuacja, gdy w tym nagłówku są używane obiekty, które nie są odniesieniami.

Unikaj tego. Użyj Pimpl, aby uniknąć umieszczania członków klasy w nagłówkach. A jeśli nie jest to kod szablonu lub potrzebujesz wsparcia, nie pisz prawdziwego kodu w nagłówkach.

Najgorszy przypadek polega na tym, że trzeba utworzyć C.h, który określa, czego potrzebują A.h i B.h.

+1

TIL: Przekazywanie dalej =) – ArniBoy

+0

Dzięki @Nicol, to dobra uwaga. Ogólnie (nie w tym konkretnym przypadku podwójnego włączenia), proszę wyjaśnić, dlaczego wolisz deklarację terminową do normalnego włączenia? – Enzo

7

Użyj Uwzględnij strażników w swoich plikach nagłówkowych. http://en.wikipedia.org/wiki/Include_guard

#ifndef MYHEADER_H 
#define MYHEADER_H 

//add decls here 

#endif 

W ten sposób, jeśli pliki nagłówkowe zawarte są więcej niż raz kompilator ignoruje je.

Zasadniczo, jeśli uwzględnisz B.h, który ma A.h, byłoby lepiej włączyć A.h i B.h do swojej aplikacji, zamiast polegać na włączeniu B.h.

Umieszczamy również tylko deklaracje w pliku nagłówkowym.

Unikaj definicji za wszelką cenę w plikach nagłówkowych.

0

strażnicy header Spróbuj dodać,

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

Nigdy nie należy dołączyć plik nagłówka dwukrotnie skutkuje redefinicji ..

0

Gdy plik zostanie dodany do nagłówka pliku to zostanie uwzględnione w części przebiegu wyprzedzającego kompilacji. Więc włączając B.h do A.h. W tym A.h w B.h. Jest to rodzaj nieskończonej rekurencji, a plik jest dołączany wiele razy.

Łącznie B.H. w A.H wynosi A.H < - B.H. Łącznie A.H w B.H. wynosi Bh < - A.H

więc jej król nieskończonej pętli rekurencyjnej.

1

Nie powiedziałeś, jakie są wzajemne zależności, więc są to tylko domysły. We wszystkich tych przypadkach zakładam, że A.h definiuje class A i B.h zdefiniowane jako class B.

Przypadek 1: Wzajemna zależność odbywa się za pomocą wskaźników lub odnośników. Na przykład class A zawiera element danych typu B* i na odwrót. W takim przypadku żaden z nagłówków nie musi być #include inny. Zamiast tego użyj zgłoszenia do przodu.

Przypadek 2: Wzajemna zależność jest przez obiekty. Na przykład class A zawiera element danych typu B i na odwrót. W tym przypadku jesteś hosed.

Przypadek 3: Mieszane zależności. Na przykład class A zawiera element danych typu B, ale class B zawiera element danych typu A*. Teraz A.h potrzebuje #include B.h, ale B.h potrzebuje tylko deklaracji forward z class A.

Powinieneś zawsze używać jakiegoś jednorazowego zabezpieczenia, aby zapobiec wielokrotnemu dołączaniu nagłówka.

1

Zakładając, że w każdym nagłówku masz klasę, można zrobić tak:

pliku nagłówka: „Ah”

#ifndef A_H 
#define A_H 
Class B; 

Class A { 
public: 
    B name_of_B_; 
} 

#endif 

Z #ifndef A_H #define A_H #endif upewnić się, że każdy nagłówek jest włączone tylko raz . Powinieneś używać tego w prawie każdym nagrywanym pliku nagłówkowym, nie tylko w tym szczególnym przypadku podwójnego włączenia. Z Class B; deklarujesz, że gdzieś zdefiniujesz klasę o nazwie "B".

Class B { 
public: 
    A name_of_A_; 
} 

#endif 

Ta sama historia jak w przypadku klasy "B". W ten sposób unikasz nieskończonego włączenia pętli.

+1

Zawarte na końcu każdego pliku nagłówkowego są całkowicie bezużyteczne. Deklaracja forward, taka jak klasa A; jest mechanizmem informującym kompilator, że klasa A będzie obecna później, tak samo dla klasy B. W tym momencie nie ma znaczenia, kiedy któraś z klas A lub B zostanie rozwiązana, ponieważ właśnie powiedział kompilatorowi, że będą tam na końcu kompilacji, korzystając z deklaracji terminowej. W związku z tym zawarte na końcu pliku nagłówkowego można usunąć, ponieważ nie służą one żadnym celom. Pozdrawiam;) – ForceMagic

+0

Dobrze! Dziękuję za wskazanie. – Enzo