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.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow