S
Question12345 schrieb:
Wie kann dann aber mein LNK 2005 entstehen. Ich habe in keiner cpp was doppelt. Nur operatoren im Header. Könnte es daran liegen?
Du bist mit dem Konzepten "Übersetzungseinheit" und "Getrennte Übersetzung" nicht vertraut. Include Guards verhindern nur das mehrfache Einbinden von Code innerhalb einer einzigen Übersetzungseinheit. Wenn die Header-Datei eine Definition einer Funktion(1) enthält, und dieser Header in mehr als eine ÜE eingebunden wird, dann wird sich der Linker beschweren. Übersetzten geht, "linken" nicht.
Ich schätze Dein Fall sieht in etwa so aus:
// header.hpp
#ifndef HEADER
#define HEADER
void foo(int x) {} // Definition
#endif
// tu1.cpp
#include "header.hpp"
// tu2.cpp
#include "header.hpp"
Dass Du die Definition nur einmal in einer Headerdatei stehen hast und die mit Includeguards geschützt hast, bringt Dir nichts, wenn Du den Header in mehreren CPP-Dateien einbindest. Die werden (logisch gesehen) unabhängig voneinander kompiliert. Dem Compiler ist das ziemlich egal, woher der ganze Code kommt. Der Preprocessor "setzt die ÜE zusammen" (fürgt Text aus anderen Dateien ein, macht die Makro-Ersetzung, etc). Wenn Du tu1.cpp und tu2.cpp kompilierst, bekommst Du zwei Objektdateien, die jeweils eine Definition von foo beinhalten. Da foo jeweils "external linkage" hat bezieht sich der Name auf diesselbe Funktion. Der Linker sieht zwei Definition, wobei nur eine erlaubt ist. ("Eine-Definition-Regel").
Lösung 1:
Definiere solche Funktionen in einer eigenen CPP-Datei und schreibe nur die Deklarationen in eine Header-Datei. (Sollte man meistens so machen)
// foo.hpp
#ifndef FOO
#define FOO
void foo(int x); // Deklaration
#endif
// foo.cpp
#include "foo.hpp"
void foo(int x) {} // Definition
// tu1.cpp
#include "header.hpp"
// tu2.cpp
#include "header.hpp"
Lösung 2:
Definiere Deine Funktion als "inline". Damit der Compiler Funktionen "inlinen" kann, muss er die Definition kennen. Dementsprechend darf die Definition in mehreren ÜEs auftauchen, vorrausgesetzt, dass es exakt die gleiche Def ist. Der Linker schmeißt Duplikate dann einfach raus.
// header.hpp
#ifndef HEADER
#define HEADER
void foo(int x) {} // Definition
#endif
// tu1.cpp
#include "header.hpp"
// tu2.cpp
#include "header.hpp"
(Für Klassendefinitionen, Funktionstemplate-Definitionen und Definitionen statischer Elemente von Klassentemplates gilt diese Ausnahme auch).
Getrennte Übersetzung: Man will einzelne .c/.cpp Dateien separat übersetzen können, ohne in andere .c/.cpp Dateien gucken zu müssen. Um Funktionen aus anderen Übersetzungseinheiten aufrufen zu können, muss der Compiler zumindest eine Deklaration der Funktion gesehen haben.
Gruß,
SP
(1: Funktion mit externer Bindung, welche keine Inline-Funktion und kein Funktionstemplate ist)