Область определения функции
- 1 year ago
- 0
- 0
Правило одного определения (One Definition Rule, ODR) — один из основных принципов языка программирования C++ . Назначение ODR состоит в том, чтобы в программе не могло появиться два или более конфликтующих между собой определения одной и той же сущности ( типа данных , переменной , функции , объекта , шаблона ). Если это правило соблюдено, программа ведёт себя так, как будто в ней существует только одно, общее определение любой сущности. Нарушение ODR, если оно не будет обнаружено при компиляции и сборке проекта, приводит к непредсказуемому поведению программы .
Синтаксис языка C++ определяет для ряда сущностей необходимость совмещения описания с объявлением, либо дублирование в объявлении описания. Это связано с отсутствием в языке полноценной поддержки модульности , из-за чего на этапе компиляции файла в его тексте (то есть самом тексте компилируемого модуля и текстах всех включённых в него заголовочных файлов ) должны содержаться достаточные для компилятора сведения обо всех используемых программных сущностях, определённых в других единицах трансляции . Так, например, для компиляции файла, в котором используется некий класс, необходимо, по меньшей мере, определение самого класса и его публичных свойств и методов , а для использования в файле встраиваемой ( inline ) функции каждый использующий файл должен включать её полный текст. Ясно, что для обеспечения согласованности программы все такие определения в пределах системы должны быть идентичны. Обычно это обеспечивается тем, что интерфейсная часть единицы трансляции описывается в соответствующем заголовочном файле, который затем подключается везде, где необходимо использовать определённые в ней сущности. Но в действительности ничто не мешает включить в разные компилируемые файлы разные описания одних и тех же элементов программы. Компилятор не сможет обнаружить такую ошибку, так как в момент трансляции он обрабатывает код только одного модуля.
Другая коллизия возможна в случае, когда в программе окажутся два различных определения одного и того же элемента, либо расхождение между внешним объявлением (со спецификатором extern) и фактическим определением того же элемента. Например, если у внешнего объявления функции и её определения окажется различное число параметров , то вызов функции будет некорректным, но компилятор не сможет этого обнаружить, так как в момент работы видит только одну единицу трансляции.
В своей знаменитой книге «Введение в язык C++» Бьёрн Страуструп приводит следующий пример:
// file1.c: int a = 1; int b = 1; extern int c;
// file2.c: int a; extern double b; extern int c;
В данном примере 3 ошибки: a определено дважды («int a;» является определением, где начальное значение a не задано), b в описании и определении имеет различные типы, а c описано дважды, но не определено. Эти виды ошибок в C++ не могут быть обнаружены компилятором . В большинстве случаев их обнаруживает компоновщик .
Ограничения, накладываемые на повторные описания и определения программных сущностей в C++, соблюдение которых гарантирует адекватную обработку таких описаний и определений, сведены в описании языка в так называемое «Правило одного определения».
Некоторые нарушения ODR могут быть найдены компилятором , но большинство из них обнаруживаются только на этапе компоновки.