2011-08-03 12 views
5

Widziałem nagłówek zawierający taki styl, w którym pliki nagłówkowe nie zawierają innych plików nagłówkowych, a odpowiednie pliki * .cpp muszą zawierać wszystkie zależności (i dołączać je w odpowiedniej kolejności). Wydaje się możliwe, że w dawnych czasach to ułatwiłoby śledzenie zależności budowania (ale po prostu zgaduję). Czy jest to dzisiaj dobry powód?Czy istnieje dobry powód, aby plik nagłówkowy C++ nie zawierał innych plików nagłówkowych?

Plik "Bh":

#ifndef _B_h_ 
#define _B_h_ 

// Note we do not #include "A.h" that contains class A declaration. 

class B 
{ 
public: 
    A a; // An A object. 
}; 
#endif // _B_h_ 

Plik "B.cpp":

#include "A.h" // Must include this before B.h, otherwise class A not defined in B.h 
#include "B.h" 

... 
+1

Możesz edytować swój własny tytuł pytania, jeśli chcesz go tak nazwać. –

+0

Wątpię, czy widzieliście * ten * przykład w prawdziwym życiu, ponieważ się nie kompiluje. Musisz mieć dostęp do pełnego typu każdego obiektu członkowskiego. –

+2

Życzenie. :) –

Odpowiedz

4

Wygląda na to, że ktokolwiek napisał ten kod, źle zrozumiał powszechną rekomendację zmniejszenia liczby zawartych nagłówków.Zazwyczaj zaleca się usunięcie niepotrzebnych dyrektyw#include <> w nadziei na przyspieszenie kompilacji. Rzeczywiście, w dużych projektach może znacznie przyspieszyć kompilację poprzez:

  1. zmniejszenie liczby plików nagłówkowych, które kompilator musi otworzyć, aby skompilować dowolny plik źródłowy;
  2. zmniejszenie liczby plików źródłowych, które należy zrekompilować po zmianie nagłówka.

Na ogół ludzie zaleci (jej było na standardy kodowania dla wszystkich projektów Mam pracował), używając do przodu deklaracje klas, chyba że klasa zdefiniowana w danym nagłówku jest:

  1. stosowany jako klasa podstawowa;
  2. używany jako element danych;
  3. ma niekompletną specyfikację urzędową (np. Standardowe kontenery biblioteki mogą mieć dodatkowe argumenty szablonu, o ile mają wartości domyślne, więc niestandardowe przekazywanie ich dalej jest deklarowane).

W przypadkach 1 i 2, dyrektywa #include <>koniecznością stawienia się przed definicją klasy w wszystkie zależne pliki źródłowe i nagłówków. Zasadniczo, po prostu przenosi dyrektywę #include <> z nagłówka do każdej z jego zależności. Powoduje to więcej kodu i nie przynosi korzyści (np. Czas kompilacji itp. Będzie taki sam). Z tego powodu tej rekomendacji towarzyszy również inny wpis w standardzie kodowania: każdy plik nagłówkowy powinien kompilować "samodzielny" (np. Umieszczony w pierwszym wierszu pliku źródłowego).

8

Tak, to byłoby złe praktyki, bo jeśli ktoś dostaje rozkaz źle dostaną błędy że mogą lub nie mogą się dowiedzieć. Jeśli wszystkie pliki nagłówkowe zawierają osłony, to jeden nagłówek zawierający wszystkie inne potrzebne nagłówki nie będzie stanowić problemu, tak powinien być.

+1

+1. Myślę, że natknąłem się na tego rodzaju problem w pewnym momencie, gdy dołączono jeden z plików nagłówkowych Window. W dokumentacji napisano coś w stylu "kiedy dołączysz X, powinieneś również uwzględnić Y". Moja myśl była "dobrze, jeśli X wymaga Y, to dlaczego X nie zawiera samego Y?". – MRAB

+0

@MRAB Pamiętam coś takiego, ale nie pamiętam, który to był nagłówek. –

+1

'' musi być zawarty przed '', lub inaczej '' zawiera '', który jest niekompatybilny (i przestarzały?). –

2

Czy ma to obecnie uzasadniony powód?

Nie, niezupełnie. Ludzie robią różne rzeczy, które "będą działać", ponieważ nie wiedzą nic lepszego, nie obchodzi ich ani nie mają ważniejszych rzeczy do zmartwienia. Dzieje się tak, gdy twój język opiera się na preprocesorze zamiast na rzeczywistym systemie importu modułów.

Powiedziałbym, że najlepszą praktyką jest upewnienie się, że osoba #, w tym Twoje rzeczy, nigdy nie musi martwić się o kolejność dołączania lub ukrywania warunków wstępnych. O ile, oczywiście, twoja ręka jest wymuszona przez głupie sztuczki makro ze strony innych osób.

4

To naprawdę kiepska praktyka. Pozwól kompilatorowi znaleźć właściwą kolejność - jest mniej podatny na błędy. Nagłówki powinny się kompilować tak, jakby były zawarte osobno - tj. Gdybyś miał JT składającą się tylko z #include "B.h".

+0

Kompilator nie może znaleźć właściwej kolejności. Nie może to być nawet właściwy porządek. –

+1

Moreso, ponieważ nie ma * żadnej możliwości *, że mógłbyś kiedykolwiek użyć 'B.h' * bez * również włączając' A.h', logiczne jest, że 'A.h' powinno być zawarte wewnątrz' B.h'. Powinieneś być w stanie powiedzieć: "Chcę klasy" B "i osiągnąć to wyłącznie przez włączenie' B.h' w żadnych okolicznościach. –

2

Tak, polecam #włączając "dowolną zależność INTERFEJSU w dowolnym nagłówku.

W tym przypadku tak: chciałbym # dołączyć "A" (ponieważ interfejs B zależy od A).

W przeciwnym razie, jeśli implementacja użyłaby "A" (ale nagłówek nie był), wstawiłbym tylko # w .cpp (ponieważ nie jest częścią interfejsu).

Pod żadnym pozorem nie chciałbym, aby kolejność nagłówków miała znaczenie, jeśli w ogóle można tego uniknąć. Zazwyczaj kolejność nagłówków NIE JEST WAŻNA.

IMHO ...

PS: Aż Bjarne Stroustrup chce inaczej, makra preprocesora i preprocesora są nadal bardzo dużo z nas. Na pewno w C-land, a już na pewno w prawie każdym API Microsoftu. To po prostu dobry sposób na poszanowanie tego faktu.

2

Rozważałbym ten zły styl. Doprowadzi to do trudnych do zrozumienia błędów.

Powodem tego może być uniknięcie rekompilacji dużej ilości kodu za każdym razem, gdy wprowadzono zmiany do pojedynczego pliku nagłówkowego. Jeśli znajdziesz się w tej sytuacji, prawdopodobnie masz problem z projektowaniem.

Powiązane problemy