Pamiętaj, że preprocesor C / C ++ to osobny, czysto tekstowy etap przetwarzania. Do #includedyrektywa ściąga treści zawarte nagłówku i kompilator musi ją przeanalizować. Co więcej, kompilacja każdego z nich .cppjest całkowicie osobna, więc fakt, że kompilator właśnie przeanalizował B.hpodczas kompilacji B.cpp, nie pomaga, gdy jest potrzebny ponownie podczas kompilacji A.cpp. I znowu podczas kompilacji C.cpp. I D.cpp… I tak dalej. I każdy z tych plików musi zostać ponownie skompilowany, jeśli jakikolwiek plik w nim się zmienił.
Powiedzmy, że klasa Aużywa klasy Bi klas Ci Dużywa klasy A, ale nie trzeba manipulować B. Jeśli klasa Amoże być zadeklarowana za pomocą tylko deklaracji forward B, niż B.hjest kompilowana dwukrotnie: podczas kompilacji B.cppi A.cpp(ponieważ Bnadal jest potrzebna w ramach Ametod).
Ale kiedy A.hobejmuje B.h, to jest kompilowany cztery razy, podczas kompilacji B.cpp, A.cpp, C.cppi D.cppjak później dwa teraz pośrednio obejmuje B.hteż.
Również, gdy nagłówek jest dołączany więcej niż jeden raz, preprocesor nadal musi go czytać za każdym razem. Pominie przetwarzanie zawartości ze względu na ochronę#ifdef , ale nadal ją odczytuje i musi szukać końca osłony, co oznacza, że musi przeanalizować wszystkie zawarte w niej dyrektywy preprocesora.
(Jak wspomniano w drugiej odpowiedzi, prekompilowane nagłówki próbują obejść ten problem, ale są one własną puszką robaków; w zasadzie można je rozsądnie wykorzystać do nagłówków systemowych i tylko wtedy, gdy nie używa się ich zbyt wielu, ale nie do nagłówki w twoim projekcie)
vehicle.h,bus.h,toybus.h.vehicle.hdołącz przezbus.hibus.hdołącz przeztoybus.h. więc jeśli coś zmieniębus.h. czy kompilator otwiera się i parsujevehicle.hponownie? czy to kompiluje to ponownie?