[C++] Mehrfachdefinition einer Funktion
-
Ich habe ein Projekt mit 3 Dateien, einer normalen main.cpp und einer Klasse Personengruppe, die in eine .h und .cpp gesplittet sind. Meine Dateien sehen wie folgt aus:
main.cpp:
#include <iostream> #include "Personengruppe.h" using namespace std; int main(){ Personengruppe gruppe_1(3); Personengruppe gruppe_2(2); // hier die beiden gruppen fuellen cout << gruppe_1.getName() << " hat im Mittel " << gruppe_1.averageScore() << " Punkte." << endl; cout << gruppe_2.getName() << " hat im Mittel " << gruppe_2.averageScore() << " Punkte." << endl; if (gruppe_1.averageScore() > gruppe_2.averageScore()) cout << "Gruppe 1 hat gewonnen!" << endl; else cout << "Gruppe 2 hat gewonnen!" << endl; return 0; }Personengruppe,h:
#ifndef PERSONENGRUPPE_H__ #define PERSONENGRUPPE_H__ #include <string> #include <iostream> using namespace std; struct Person{ string name; int score; }; // liest genau eine Person ein Person readPerson(){ string name; int score; cout << "Name der Person eingeben: "; cin >> name; cout << "Score der Person eingeben: "; cin >> score; Person p = {name, score}; return p; } class Personengruppe { private: string name; int quantity; Person* group; public: Personengruppe(int anzahl); string getName(); void setName(string name); int getQuantity(); void setQuantity(int quantity); Person* getGroup(); void setGroup(Person* group); int averageScore() const; void addPerson(Person p); }; #endifPersonengruppe.cpp
#include "Personengruppe.h" //Konstruktor Personengruppe::Personengruppe(int anzahl) :quantity(anzahl) { this->group = new Person[quantity]; for(int i=0; i<anzahl; i++) { group[i] = readPerson(); } } //Set- und get Methoden string Personengruppe::getName() { return this->name; } void Personengruppe::setName(string name) { this->name = name; } int Personengruppe::getQuantity() { return this->quantity; } void Personengruppe::setQuantity(int quantity) { this->quantity = quantity; } Person* Personengruppe::getGroup() { return group; } void Personengruppe::setGroup(Person* group) { this->group = group; } //Weitere Methoden int Personengruppe::averageScore() const { int score = 0; for( int i = 0; i < this->quantity ; i++) { score += this->group[i].score; } return ( score / this->quantity ); } void Personengruppe::addPerson(Person p){ Person* newGroup = new Person[this->quantity + 1]; for ( int i = 0; i < this->quantity; i++ ) { newGroup[i] = this->group[i]; } this->quantity = this->quantity + 1; newGroup[this->quantity-1] = p; delete[] group; group = newGroup; }Wenn ich das Projekt nun kompilieren möchte, bekomme ich die Fehlermeldung, die Methode readPerson(); wäre mehrfach definiert. Dies sollte mein #ifndef-Block aber doch verhindern, oder nicht? Dazu sollte ich sagen, dass ich die Datei Personengruppe.h bis auf den Teil der in class Personengruppe{..} steht so vorgegeben bekam. Was kann ich jetzt damit machen?
-
Du solltest Funktionen entweder in der Source definieren (und im Header nur deklarieren), oder im Header definieren aber mit
inline-specifier.Kurz: Kopiere einfach die Funktionsdefinition von
readPersonvon Personengruppe.h nach Personengruppe.cpp.
-
Kalkihe schrieb:
Wenn ich das Projekt nun kompilieren möchte, bekomme ich die Fehlermeldung, die Methode readPerson(); wäre mehrfach definiert.
Ist es ja auch? Die Definition von readPerson() steht in deinem Header. Damit steht diese Definition dann in jedem .cpp File, welches diesen Header inkludiert. Schau dir mal an, für was das Schlüssenwort inline gut ist...

Kalkihe schrieb:
Dies sollte mein #ifndef-Block aber doch verhindern, oder nicht?
Wie genau sollte der das deiner Meinung nach denn verhindern?

-
Noch eine Erklärung zu ifdef, da du das falsch verstanden hast:
Die ganzen Präprozessoranweisungen arbeiten als reine Textersetzungsmakros, lange vor dem Compiler oder gar Linker. Die verstehen nichts von der Sprache C++, die verstehen auch nichts von verschiedenen Übersetzungseinheiten. Es wird einfach eine Datei genommen und bei jedem Präprozessormakro wird eine entsprechende Textersetzung vorgenommen.Hier passiert also folgendes:
main.cpp wird genommen,#include "Personengruppe.h"wird durchgeführt, nun steht der Inhalt von Personengruppe.h an der Stelle. Dessen Inhalt wird auch verarbeitet. PERSONENGRUPPE_H__ ist nicht definiert, also wird es definiert und der restliche Inhalt der Datei bleibt unverändert. Dann wird main.cpp compiliert und die Daten gehen an den Linker.
Dann wird nochmal ganz neu angefangen mit Personengruppe.cpp:#include "Personengruppe.h"wird durchgeführt, nun steht der Inhalt von Personengruppe.h an der Stelle. Dessen Inhalt wird auch verarbeitet. PERSONENGRUPPE_H__ ist nicht definiert, also wird es definiert und der restliche Inhalt der Datei bleibt unverändert. Dann wird personengruppe.cpp compiliert und die Daten gehen an den Linker.
Dann kommt der Linker dran, der sieht in beiden eine Definition von Person readPerson() und beschwert sich.Die Includeguards sind dazu da, um zu verhindern, dass ein Header mehrmals (oder in falscher Reihenfolge) in einer Übersetzungseinheit eingebunden wird. Dies käme sonst sehr oft vor, weil man oft etwas in dieser Art hat:
A.h:#include <iostream> // ...B.h:
#include <iostream> // ...main.cpp:
#include "A.h" #include "B.h"Dann ist es wichtig, dass im Header iostream Includeguards sind.
Mehrere Übersetzungseinheiten hingegen sind völlig unabhängig für den Präprozessor