C++
One Definition Rule (ODR)
Sök…
Multipeldefinierad funktion
Den viktigaste konsekvensen av One Definition-regeln är att icke-inline-funktioner med extern länkning endast ska definieras en gång i ett program, även om de kan deklareras flera gånger. Därför bör sådana funktioner inte definieras i rubriker, eftersom en rubrik kan inkluderas flera gånger från olika översättningsenheter.
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();
}
I detta program definieras funktionen foo
i rubriken foo.h
, som ingår två gånger: en gång från foo.cpp
och en gång från main.cpp
. Varje översättningsenhet innehåller därför sin egen definition av foo
. Observera att inkluderingsskydd i foo.h
inte förhindrar att detta händer, eftersom foo.cpp
och main.cpp
båda separat innehåller foo.h
Det mest troliga resultatet av att försöka bygga detta program är ett länk-tidfel som identifierar att foo
har multiplicerats.
För att undvika sådana fel bör man deklarera funktioner i rubriker och definiera dem i motsvarande .cpp
filer, med några undantag (se andra exempel).
Inlinefunktioner
En funktion som förklaras inline
kan definieras i flera översättningsenheter, förutsatt att alla definitioner är identiska. Det måste också definieras i varje översättningsenhet där den används. Därför bör inlinefunktioner definieras i rubriker och det finns inget behov av att nämna dem i implementeringsfilen.
Programmet kommer att bete sig som om det finns en enda definition av funktionen.
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();
}
I detta exempel enklare funktionen foo
definieras inline i huvudet fil medan de mer komplicerade funktionen bar
är inte inline och definieras i genomförandet filen. Både foo.cpp
och main.cpp
översättningsenheter innehåller definitioner av foo
, men detta program är välformat eftersom foo
är inline.
En funktion som definieras inom en klassdefinition (som kan vara en medlemsfunktion eller en vänfunktion) är implicit inline. Därför, om en klass definieras i en rubrik, kan medlemmens funktioner i klassen definieras inom klassdefinitionen, även om definitionerna kan inkluderas i flera översättningsenheter:
// in foo.h
class Foo {
void bar() { std::cout << "bar"; }
void baz();
};
// in foo.cpp
void Foo::baz() {
// definition
}
Funktionen Foo::baz
definieras utanför linjen, så den är inte en inline-funktion och får inte definieras i rubriken.
ODR-kränkning via överbelastningsupplösning
Även med identiska symboler för inlinefunktioner kan ODR kränkas om uppslag av namn inte hänvisar till samma enhet. låt oss överväga func
i följande:
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)` }
Vi har en ODR-kränkning eftersom overloaded
hänvisar till olika enheter beroende på översättningsenheten.