C++
One Definition Rule (ODR)
Zoeken…
Vermenigvuldig gedefinieerde functie
Het belangrijkste gevolg van de One Definition-regel is dat niet-inline functies met externe koppeling slechts eenmaal in een programma moeten worden gedefinieerd, hoewel ze meerdere keren kunnen worden verklaard. Daarom moeten dergelijke functies niet in kopteksten worden gedefinieerd, omdat een koptekst meerdere keren uit verschillende vertaaleenheden kan worden opgenomen.
foo.h
:
#ifndef FOO_H
#define FOO_H
#include <iostream>
void foo() { std::cout << "foo"; }
void bar();
#endif
foo.cpp
:
#include "foo.h"
void bar() { std:: cout << "bar"; }
main.cpp
:
#include "foo.h"
int main() {
foo();
bar();
}
In dit programma is de functie foo
gedefinieerd in de kop foo.h
, die twee keer is opgenomen: eenmaal van foo.cpp
en eenmaal van main.cpp
. Elke vertaaleenheid heeft daarom zijn eigen definitie van foo
. Merk op dat de include-bewakers in foo.h
dit niet voorkomen, omdat foo.cpp
en main.cpp
beide afzonderlijk foo.h
. Het meest waarschijnlijke resultaat van het proberen om dit programma te bouwen is een link-time fout die foo
identificeert als meervoudig gedefinieerd.
Om dergelijke fouten te voorkomen, moet men functies in headers declareren en deze in de overeenkomstige .cpp
bestanden definiëren , met enkele uitzonderingen (zie andere voorbeelden).
Inline functies
Een inline
gedeclareerde functie kan in meerdere vertaaleenheden worden gedefinieerd, op voorwaarde dat alle definities identiek zijn. Het moet ook worden gedefinieerd in elke vertaaleenheid waarin het wordt gebruikt. Daarom moet inline functies worden gedefinieerd in headers en er is geen noodzaak om ze te vermelden in de uitvoering bestand.
Het programma zal zich gedragen alsof er een enkele definitie van de functie is.
foo.h
:
#ifndef FOO_H
#define FOO_H
#include <iostream>
inline void foo() { std::cout << "foo"; }
void bar();
#endif
foo.cpp
:
#include "foo.h"
void bar() {
// more complicated definition
}
main.cpp
:
#include "foo.h"
int main() {
foo();
bar();
}
In dit voorbeeld is de eenvoudigere functie foo
wordt inline gedefinieerd in het header-bestand terwijl de meer gecompliceerde functie bar
is niet inline en wordt gedefinieerd in de uitvoering bestand. Zowel de vertalingseenheden foo.cpp
als main.cpp
bevatten definities van foo
, maar dit programma is goed gevormd omdat foo
inline is.
Een functie gedefinieerd binnen een klassedefinitie (die een ledenfunctie of een vriendenfunctie kan zijn) is impliciet inline. Als een klasse in een koptekst wordt gedefinieerd, kunnen daarom lidfuncties van de klasse worden gedefinieerd in de klassedefinitie, hoewel de definities kunnen worden opgenomen in meerdere vertaaleenheden:
// in foo.h
class Foo {
void bar() { std::cout << "bar"; }
void baz();
};
// in foo.cpp
void Foo::baz() {
// definition
}
De functie Foo::baz
is out-of-line gedefinieerd, dus het is geen inline-functie en mag niet worden gedefinieerd in de koptekst.
ODR-overtreding via overbelastingsresolutie
Zelfs met identieke tokens voor inline-functies kan ODR worden geschonden als het opzoeken van namen niet naar dezelfde entiteit verwijst. laten we func
overwegen in het volgende:
header.h
void overloaded(int); inline void func() { overloaded('*'); }
foo.cpp
#include "header.h" void foo() { func(); // `overloaded` refers to `void overloaded(int)` }
bar.cpp
void overloaded(char); // can come from other include #include "header.h" void bar() { func(); // `overloaded` refers to `void overloaded(char)` }
We hebben een ODR-overtreding, omdat overloaded
verwijst naar verschillende entiteiten, afhankelijk van de vertaaleenheid.