Mehrfachdefinition, Pragma Once
-
Hallo zusammen,
ich bin gerade ein wenig verwirrt und vielleicht kann mir jemand weiterhelfen.
Ich habe in meinem Programm eine Mehrfacheinbindung von Headerfiles, wodurch ich einen Linkerfehler bekomme, der mir sagt, dass die Klasse schon in anderen Objekten definiert ist. Das ist soweit logisch. Was ich nicht verstehe ist, dass ich dieser Klasse ein pragma once vorangestellt habe, was eigentlich heißen sollte, dass der Compiler die Klasse nicht mehrfach einbinden/kompilieren soll.
Habe ich hier etwas übersehen oder falsch verstanden?
Vielen Dank schon mal...Kai
-
Das kommt auf den Compiler an. Der MSVC wird das wahrscheinlich so verstehen (wie du meinst), der GCC oder sonstwer nicht unbedingt.
Welchen Compiler nutzt du denn?
Edit: ok, laut Wikipedia unterstützen das viele Compiler (beide oben genannten)... [Quelle]
-
Eine Mehrfachdefinition ist idR kein Problem von pragma once oder sonstigen Include Guards sondern heisst, dass man eine ODR-Verletzung hat.
-
Ich benutze Visual Studio. Das sollte die direktive eigentlich verstehen.
Ich habe gerade mal nachgeschaut, ob andere Klassen betroffen sind. Das ist nicht der Fall. Hier funktioniert es. Da der Unterschied dieser zu den anderen Klassen ist, dass es eine statische Klasse ist, denke ich, dass es damit etwas zu tuen haben könnte. Kann das sein?
-
Ja, statische Member müssen ausserhalb der Header definiert werden (sie werden ja in den headern deklariert), ansonsten gibt es Mehrfachdefinitionen, nämlich genau so viele wie oft du den Header einbindest
-
Achso, dann ist das der Fehler. Ich versuche das mal kurz umzubauen...
-
Kaiaiai, das Konzept der getrennten Übersetzung sowie die "One-Definition-Rule" sollte dir bekannt sein. Hol das bitte nach.
Kaiaiai schrieb:
Ich habe in meinem Programm eine Mehrfacheinbindung von Headerfiles, wodurch ich einen Linkerfehler bekomme, der mir sagt, dass die Klasse schon in anderen Objekten definiert ist.
In diesem Satz scheinen schon ganz viele Missverständnisse durch. Wenn der Inhalt eines Headers mehrfach in eine Übersetzungseinheit eingefügt wird, ohne dass man sich davor schützt per Include Guard oder auch pramga once, dann wird es wenn überhaupt einen Fehler zur Compile-Zeit geben. Deinen Linkerfehler hast du bekommen, weil du die ODR (one definition rule) verletzt hast und dies dem Linker in dieser Situation aufgefallen ist. Solche Verletzungen haben nichts mit Include-Guards zu tun. Es ist dein Fehler, eine Definition von etwas in eine Header-Datei reingeschrieben zu haben, die da überhaupt nichts zu suchen hat, weil zwei oder mehrere cpp-Dateien diesen Header inkludieren und damit die Definition mehrfach vorhanden ist. Es ist übrigens kein Fehler, mehrere Definitionen einer Klasse in seinem Programm zu haben, so lang sie äquivalent sind. Es ist aber ein Fehler, mehrere Definitionen von etwas in ein und derselben Übersetzungseinheit zu haben. Genau davor schützen Include-Guards. Es ist auch ein Fehler mehrere Definitionen einer statischen Klassenvariablen über mehrere Übersetzungseinheiten zu verteilen. Das können Include-Guards nicht verhindern. Du musst das verhindern, indem du diese Definition aus dem Header rausnimmst und in eine cpp-Datei reinpackst. Dann gibt es diese Definition Programm-weit eben nur einmal, so wie es sein soll.
Kaiaiai schrieb:
Habe ich hier etwas übersehen oder falsch verstanden?
Ja.
-
Mmmhhh. Ok, ich habe mir die ODR gerade angeschaut.Das mehrfache Definitionen nicht möglich sind, war mir auch bewusst. Ansonsten wären ja die Funktionen nicht eindeutig. Normalerweise trenn ich auch Deklaration und Definition, aber bei der Klasse handelt es sich um ein Fremdfabrikat, in dem alles in einem File ist. Ich habe jetzt alle Definitionen dieser in eine .cpp gepackt. Nun kompiliert VS, aber die Klasse funktioniert nicht mehr...immerhin ich bin schon mal einen Schritt weiter...
-
Vielleicht hilft dir da das Pimpl-Idiom. Du veränderst damit die fremde Klasse nicht, aber kannst sie abkapseln. Das äußerliche Interface kannst du ja ohne Probleme übernehmen, nur für die statischen Teile musst du dir dann was einfallen lassen
-
Habs geschafft. Die Klasse ist jetzt umgeschrieben und es funktioniert. Danke für die Tips.
-
"inline" vor die Funktions-Definitionen schreiben wirkt auch Wunder.
Natürlich nicht bei statischen Membern, aber davon sollte man sowieso keine haben.