Suche…


Mehrfach definierte Funktion

Die wichtigste Konsequenz der One-Definition-Regel ist, dass Nicht-Inline-Funktionen mit externer Verknüpfung nur einmal in einem Programm definiert werden sollten, obwohl sie mehrmals deklariert werden können. Daher sollten solche Funktionen nicht in Headern definiert werden, da ein Header aus verschiedenen Übersetzungseinheiten mehrfach eingefügt werden kann.

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 diesem Programm ist die Funktion foo im Header foo.h , der zweimal enthalten ist: einmal aus foo.cpp und einmal aus main.cpp . Jede Übersetzungseinheit enthält daher ihre eigene Definition von foo . Beachten Sie, dass die Include-Guards in foo.h dies nicht verhindern, da foo.cpp und main.cpp beide foo.h separat enthalten. Das wahrscheinlichste Ergebnis des Versuchs, dieses Programm zu erstellen, ist ein Verbindungszeitfehler, der foo als mehrfach definiert identifiziert.

Um solche Fehler zu vermeiden, sollte man Funktionen in Header deklariert und definiert sie in den entsprechenden .cpp - Dateien, mit einigen Ausnahmen (andere siehe Beispiele).

Inline-Funktionen

Eine inline deklarierte Funktion kann in mehreren Übersetzungseinheiten definiert werden, vorausgesetzt, dass alle Definitionen identisch sind. Es muss auch in jeder Übersetzungseinheit definiert werden, in der es verwendet wird. Inline-Funktionen sollten daher in Kopfzeilen definiert werden und müssen nicht in der Implementierungsdatei erwähnt werden.

Das Programm verhält sich so, als ob es eine einzige Definition der Funktion gibt.

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 diesem Beispiel ist die einfachere Funktion foo wird inline in der Header - Datei definiert , während das kompliziertere Funktion bar nicht inline ist und in der Implementierungsdatei definiert. Sowohl die foo.cpp und main.cpp Übersetzungseinheiten enthalten Definitionen von foo , aber dieses Programm ist gut gebildet , da foo inline ist.

Eine in einer Klassendefinition definierte Funktion (die eine Member- oder eine Friend-Funktion sein kann) ist implizit inline. Wenn also eine Klasse in einem Header definiert ist, können Member-Funktionen der Klasse innerhalb der Klassendefinition definiert werden, auch wenn die Definitionen in mehreren Übersetzungseinheiten enthalten sind:

// in foo.h
class Foo {
    void bar() { std::cout << "bar"; }
    void baz();
};

// in foo.cpp
void Foo::baz() {
   // definition
}

Die Funktion Foo::baz ist als Out-of-Line definiert, es handelt sich also nicht um eine Inline-Funktion und darf nicht im Header definiert werden.

ODR-Verletzung durch Überlastlösung

Selbst bei identischen Token für Inline-Funktionen kann ODR verletzt werden, wenn das Nachschlagen von Namen nicht auf dieselbe Entität verweist. Betrachten wir func im Folgenden:

  • 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)`
    }
    

Wir haben eine ODR-Verletzung, da overloaded abhängig von der Übersetzungseinheit auf verschiedene Entitäten verweist.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow