PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++: "...multiple definition..."


pajofego
2005-04-27, 21:51:35
Ich möchte folgende Exception Klasse für meinen Code benutzen:

#include <iostream>

using namespace std;

class FluidException
{
private:
short errNum;
static const char *pErrText[];
public:
enum {ZDIV, SQRT};
FluidException(int err)
{
errNum = err;
}
FluidException(const FluidException& src)
{
errNum = src.errNum;
}
friend ostream& operator << (ostream& os, const FluidException& e);
};
// Feld mit Fehlermeldungen
const char *FluidException::pErrText[] =
{
"Division durch 0",
"Wurzel aus negativer Zahl"
};

inline ostream& operator <<(ostream& os, const FluidException& e)
{
os << "Fehler " <<
e.pErrText[e.errNum] <<
" aufgetreten!\n";
return os;
}


Wenn ich diese Klasse in mein Code einfüge, kommt folgende Fehlermeldung:

multiple definition of 'FluidException::pErrText'

first defined here (-> Verweist auf die Datei: locale_facets.tcc) :confused:

Weiß einer von euch was die Ursache dafür ist? Habe bis jetzt keine Funktion aus der Exception Klasse (FluidException) aufgerufen, nur die Datei in mein Code eingefügt...

Danke,

Gruß

pajofego

Neomi
2005-04-27, 23:10:55
Ich vermute mal, daß es sich um eine Headerdatei handelt und diese in mehreren anderen Dateien eingebunden wird, wenn auch über Umwege. Eben das gleiche Problem wie mit globalen Variablen in einer Headerdatei. Die werden ja auch nicht in Headerdateien definiert, sondern nur den anderen Dateien "vorgestellt".

// Feld mit Fehlermeldungen
const char *FluidException::pErrText[] =
{
"Division durch 0",
"Wurzel aus negativer Zahl"
};

Stell das einfach in eine Sourcendatei. Die wird ja nicht wie eine Headerdatei eingebunden, sondern nur einmalig compiliert. Dann sollte es gehen.

pajofego
2005-04-27, 23:21:25
Ich vermute mal, daß es sich um eine Headerdatei handelt und diese in mehreren anderen Dateien eingebunden wird, wenn auch über Umwege. Eben das gleiche Problem wie mit globalen Variablen in einer Headerdatei. Die werden ja auch nicht in Headerdateien definiert, sondern nur den anderen Dateien "vorgestellt".

// Feld mit Fehlermeldungen
const char *FluidException::pErrText[] =
{
"Division durch 0",
"Wurzel aus negativer Zahl"
};

Stell das einfach in eine Sourcendatei. Die wird ja nicht wie eine Headerdatei eingebunden, sondern nur einmalig compiliert. Dann sollte es gehen.


Danke, das war die Lösung...ich kämpfe mich leider widerwillig durch C++ :(

Grestorn
2005-04-28, 08:05:13
Danke, das war die Lösung...ich kämpfe mich leider widerwillig durch C++ :(
Tipp:

Man sollte jedes .h File in einen folgenden Block einschließen:

#ifndef <NameDerIncludeDatei>
#define <NameDerIncludeDatei> 1

.... // Hier der vollständige Inhalt der Datei

#endif


Dadurch wird sichergestellt, dass auch wenn eine Include-Datei mehrfach includiert wird (was sich gar nicht vermeiden lässt), der Inhalt nur einmal gelesen wird und es zu keinen Konflikten kommt.

del_4901
2005-04-28, 10:29:33
Cirkelschlüsse und andere "Spässe des Linkers" lassen sich auch vermeiden indem man zusätzlich dazu noch für seine Klassen Prototypen deklariert.


class blah; // das Packt man ganz nach oben nach den Präpozesserdirektiven

// irgendwann kommt dann:
class blah
{
...
};

Neomi
2005-04-28, 13:24:56
Dadurch wird sichergestellt, dass auch wenn eine Include-Datei mehrfach includiert wird (was sich gar nicht vermeiden lässt), der Inhalt nur einmal gelesen wird und es zu keinen Konflikten kommt.

Böse Falle, sehr böse Falle. Für Deklarationen stimmt das, Definitionen haben da aber andere Ansprüche. Letztendlich wird dadurch nur verhindert, daß eine Headerdatei mehrfach (z.B. durch andere Headerdateien) innerhalb einer einzigen Sourcendatei inkludiert wird. Wenn du aber trotz dieses Schutzes (der natürlich trotzdem sein muß) Variablen in einer Headerdatei definierst, wird entweder der Linker meckern oder jede Sourcendatei auf ihre eigene Kopie dieser Variablen zugreifen.

Grestorn
2005-04-29, 08:11:29
Böse Falle, sehr böse Falle. Für Deklarationen stimmt das, Definitionen haben da aber andere Ansprüche. Letztendlich wird dadurch nur verhindert, daß eine Headerdatei mehrfach (z.B. durch andere Headerdateien) innerhalb einer einzigen Sourcendatei inkludiert wird. Wenn du aber trotz dieses Schutzes (der natürlich trotzdem sein muß) Variablen in einer Headerdatei definierst, wird entweder der Linker meckern oder jede Sourcendatei auf ihre eigene Kopie dieser Variablen zugreifen.
In einer Headerdatei wird NICHTS definiert. Immer nur deklariert. Das ist eine der ersten Regeln, die man lernt. Eine Headerdatei darf nie von sich aus Code erzeugen (und das tut sie, so bald man eine Variable darin definiert).

Beispiel für eine statische Membervariable:

Headerdatei xy.h:
class xy
{
static int bla;
}

Code Datei xy.cpp:
int xy::bla = 0;

Globale Variablen, so man sie wirklich verwenden will/muss, werden in der Header-Datei mit dem Wörtchen "extern" lediglich deklariert und in irgendeiner Code-Datei dann definiert.

Grestorn
2005-04-29, 08:14:34
Cirkelschlüsse und andere "Spässe des Linkers" lassen sich auch vermeiden indem man zusätzlich dazu noch für seine Klassen Prototypen deklariert.

Man kann mit Forwarding zwar viele Includes vermeiden, aber Leider ist das kein Allheilmittel. Wenn Du eine Klasse vollständig in einer anderen Klasse aggregierst (also eine Membervariable vom Typ einer anderen Klasse direkt, nicht als Referenz oder Pointer), dann musst Du die verwendete Klasse includieren, damit der Compiler weiß, wie groß diese ist.

Auch wenn Du von einer Klasse ableitest, musst Du die Basisklasse vollständig includieren.

Neomi
2005-04-29, 12:12:29
In einer Headerdatei wird NICHTS definiert. Immer nur deklariert.

Klar, du hast Recht. Wenn ich dich besser kennen würde (bin ja noch nicht lange hier), hätte ich das wohl auch direkt aus deinem Posting rausgelesen. Das klang für mich aber erstmal so, als würdest du das übliche "#ifndef -> #define -> ... -> #endif" als Alternative zur Definition in einer Sourcendatei sehen. Falsche Interpretation meinerseits.

Coda
2005-04-29, 13:20:34
In einer Headerdatei wird NICHTS definiert. Immer nur deklariert. Außer Templates :rolleyes:

Neomi
2005-04-29, 14:45:16
Außer Templates :rolleyes:

Templates sind ja auch keine echten Definitionen. Es wird kein Code erzeugt, bloß die Vorlage dafür geliefert.