Правило одного визначення (One Definition Rule, ODR) — важлива концепція в мові програмування C++, що визначена в ISO C++ Standard(ISO/IEC 14882) 2003, в розділі 3.2.
Коротко ODR стверджує: В окремій одиниці трансляції (і, якщо конкретна реалізація зберігає тексти програм у файлах, після обробки препроцесором) шаблон, клас, функція, об'єкт, або перерахування можуть мати не більше одного визначення. Хоча деякі можуть мати яку завгодно кількість оголошень. В програмі об'єкт або невставна функція не можуть мати більш ніж одне визначення. Якщо об'єкт чи невставна функція не використовуються, тоді достатньо оголошення без визначення. У випадку використання вони повинні мати рівно одне визначення. Деякі сутності, наприклад, класи, шаблони або вставні функції можуть мати більш ніж одне визначення тільки якщо: вони містяться в різних одиницях трансляції; вони ідентичні лексема за лексемою; значення лексем однакові в обох одиницях трансляції.
Компілятори не завжди знаходять порушення ODR. Багато з них виявляє компонувальник.
Приклади
//file 1.c struct S { int a; char b; }; void f(S*);
//file 2.c struct S { int a; char b; }; void f(S*) { /* ... */ }; Правило ODR каже, що цей приклад дозволений, і в обох файлах під S буде матися на увазі одна і та сама структура. Хоча це й невдалий спосіб описання структур, оскільки людина, яка супроводжує file2.c, може припустити, що визначення в її файлі єдине і вважатиме, що його можна змінювати, що може призвести до помилок, які буде складно знайти.
Метою ODR є реалізація можливості включення визначення класу в різні одиниці трансляції з одного заголовного файлу. //file s.h struct S { int a; char b; }; void f(S*);
//file 1.c #include "s.h" // використання f()
//file 1.c #include "s.h" void f(S*) { /* ... */ };
Наведемо приклад трьох випадків порушення правила ODR:
//file 1.c struct S1 { int a; char b; }; struct S1 { int a; char b; }; // помилка: повторне визначення Структуру не можна двічі визначити в одному файлі. //file 1.c struct S2 { int a; char b; };
//file 1.c struct S2 { int a; char bb; }; // помилка Не ідентичні лексема за лексемою. //file 1.c typedef int X; struct S3 { X a; char b; };
//file 2.c typedef char X; struct S3 { X a; char b; }; // помилка Значення лексем різне в різних одиницях трансляції.
Джерела Мова програмування С++ by Bjarne Stroustrup — Addison-Wesley Pub Co; 3rd edition (February 15, 2000); ISBN 0-201-70073-5