Стандарты программирования на С++. 101 правило и рекомендация | страница 104



, но >f(int) будет невидима для >B::g, если ее объявление окажется после объявления >using.

Рассмотрим два частных случая. Пусть фрагменты 1, 2 и 3 находятся в трех различных заголовочных файлах >s1.h, >s2.h и >s3.h, а фрагмент 4 — в файле реализации >s4.срр, который включает указанные заголовочные файлы. Тогда семантика >B::g зависит от порядка, в котором заголовочные файлы включены в >s4.срр! В частности:

• если >s3.h идет перед >s2.h, то >B::g будет вызывать >A::f(int);

• иначе если >s1.h идет перед >s2.h, то >B::g будет вызывать >A::f(doublе);

• иначе >B::g не будет компилироваться вовсе.

В описанной ситуации имеется один вполне определенный порядок, при котором все работает так, как должно.

Давайте теперь рассмотрим ситуацию, когда фрагменты 1, 2, 3 и 4 находятся в четырех различных заголовочных файлах >s1.h, >s2.h, >s3.h и >s4.h. Теперь все становится существенно хуже: семантика >B::g зависит от порядка включения заголовочных файлов не только в >s4.h, но и в любой код, который включает >s4.h! В частности, файл реализации >client_code.срр может пытаться включить заголовочные файлы в любом порядке:

• если >s3.h идет перед >s2.h, то >B::g будет вызывать >A::f(int);

• иначе если >s1.h идет перед >s2.h, то >B::g будет вызывать >A::f(doublе);

• иначе >B::g не будет компилироваться вовсе.

Ситуация стала хуже потому, что два файла реализации могут включать заголовочные файлы в разном порядке. Что произойдет, если >client_code_1.срр включает >s1.h, >s2.h и >s4.h в указанном порядке, a >client_code_2.срр включает в соответствующем порядке >s3.h, >s2.h и >s4.h? Тогда >B::g нарушает правило одного определения (one definition rule — ODR), поскольку имеются две несогласующиеся несовместимые реализации, которые не могут быть верными одновременно: одна из них пытается вызвать >A::f(int), а вторая — >A::f(doublе).

Поэтому никогда не используйте директивы и объявления >using для пространств имен в заголовочных файлах либо перед директивой >#include в файле реализации. В случае нарушения этого правила вы несете ответственность за возможное изменение смысла следующего за >using кода, например, вследствие загрязнения пространства имен или неполного списка импортируемых имен. (Обратите внимание на "директивы и объявления >using для пространств имен". Указанное правило неприменимо при описании члена класса с помощью объявления >using для внесения, при необходимости, имен из базового класса.)

Во всех заголовочных файлах, как и в файлах реализации до последней директивы