Вопрос 1: Я думаю, что все, что вам не хватает, это разница между "f2 включает в себя f1", и "f2 это гарантировано для включения f1".Это особенно важно для стандартных заголовков, поскольку любой стандартный заголовок позволяет включать любые другие.Поэтому, если вы полагаетесь на косвенные включения, которые работают на вашем компьютере, ваш код может не скомпилироваться в другой реализации C ++.
Если у вас есть библиотека, в которой документация для «f2.h» говорит или подразумевает, чтоон включает в себя «f1.h», что означает, что он всегда будет во всех совместимых версиях, поэтому вы можете положиться на косвенное включение.Вы можете сделать это, когда вы используете один компонент библиотеки, который в своей основе опирается на другой компонент этой библиотеки, но где другой компонент может использоваться изолированно другими пользователями.В качестве гипотетического примера «xhtml_parser.h» может обоснованно задокументировать, что он предоставляет все определения из «xml_parser.h», а также некоторые дополнительные.
Вопрос 2: Хм, вы бы хотели перефразировать вопрос?«f2 включает в себя f1 и f2 включает в себя f1» - это не то, что вы имели в виду, и нет «круговой связи».Это может вызывать проблемы, если вы пишете заголовки так, что f1 включает в себя f2, а f2 включает в себя f1, потому что include - это не "linkage", это в значительной степени вырезка и вставка содержимого другого заголовочного файла.
Таким образом, даже до того, как на снимке появится f3, циклические включения могут быть проблематичными:
f1.h
----
#ifndef f1_h_included
#define f1_h_included
#include "f2.h"
struct DerivedA : BaseA {};
struct BaseB {};
#endif
f2.h
----
#ifndef f2_h_included
#define f2_h_included
#include "f1.h"
struct BaseA {};
struct DerivedB : BaseB {};
#endif
Это не скомпилируется, независимо от того, что вы включаете из "f1.h" и "f2.час".Предполагая, что f1 включается первым, результат после предварительной обработки выглядит следующим образом:
// contents of f2.h, pasted in at line 4 of f1.h
// (contents of f1.h on the circular include are ignored due to include guard)
struct BaseA {};
struct DerivedB : BaseB {};
// rest of f1.h
struct DerivedA : BaseA {};
struct BaseB {};
И поэтому DerivedB определяет базовый класс, который еще не был определен.Включите их наоборот, та же проблема с DerivedA.