[C++] Konstruktoren-Problem

PlaciD

Böhser Onkel
ID: 55555
L
11 Februar 2007
722
105
Hi,

ich sitze hier grad an einer eigentlich einfachen Programmieraufgabe. Leider muss ich in C++ programmieren, und als Java-Liebhaber verzweifel ich an dieser dämlichen Sprache. Ich weiß nicht, wer sich sowas ausdenkt, aber das ist ja echt unschön :-?

Naja, egal, zurück zum Thema.

Folgende Klasse:
PHP:
#include <string>
#include <sstream>

using namespace std;

class Zeit {
    
    private:
        int stunden;
        int minuten;
        int sekunden;
        string IntToString(int i);
    
    public:
        // Defaultkonstruktor
        Zeit(void);
        //normaler Konstruktor
        Zeit(int std, int min, int sec);
        
        void setZeit(int std, int min, int sec);
        string getZeit();
        
};

Zeit::Zeit(void){
    setZeit(0,0,0);
};

Zeit::Zeit(int std, int min, int sec){
    setZeit(std,min,sec);
};

void Zeit::setZeit(int std, int min, int sec){
    stunden = std;
    minuten = min;
    sekunden = sec;
};

string Zeit::getZeit(){
    return(IntToString(stunden));
};

/* METHODE kopiert und modifziert von 
 * https://fara.cs.uni-potsdam.de/%7Ekaufmann/?page=GenCppFaqs&faq=IntToString#Answ
 */
string Zeit::IntToString(int i){
    ostringstream temp;
    temp << i;
    
    return(temp.str());
};
Leider spuckt der Compiler folgendes aus:
Compiler: Default compiler
Building Makefile: "C:\Dokumente und Einstellungen\Admin\workspace\PSTA2\Makefile.win"
Executing make...
make.exe -f "C:\Dokumente und Einstellungen\Admin\workspace\PSTA2\Makefile.win" all
g++.exe main.o Laeufer.o Geschlecht.o Zeit.o Verein.o -o "psta2.exe" -L"C:/Programme/Cpp/Dev-Cpp/lib"

Laeufer.o(.text+0x100):Laeufer.cpp: multiple definition of `Zeit::Zeit()'
main.o(.text+0x100):main.cpp: first defined here
Laeufer.o(.text+0x12c):Laeufer.cpp: multiple definition of `Zeit::Zeit()'
main.o(.text+0x12c):main.cpp: first defined here
Laeufer.o(.text+0x158):Laeufer.cpp: multiple definition of `Zeit::Zeit(int, int, int)'
main.o(.text+0x158):main.cpp: first defined here
Laeufer.o(.text+0x180):Laeufer.cpp: multiple definition of `Zeit::Zeit(int, int, int)'
main.o(.text+0x180):main.cpp: first defined here
Laeufer.o(.text+0x1c8):Laeufer.cpp: multiple definition of `Zeit::getZeit()'
main.o(.text+0x1c8):main.cpp: first defined here
Laeufer.o(.text+0x1f6):Laeufer.cpp: multiple definition of `Zeit::IntToString(int)'
main.o(.text+0x1f6):main.cpp: first defined here
Laeufer.o(.text+0x1a8):Laeufer.cpp: multiple definition of `Zeit::setZeit(int, int, int)'
main.o(.text+0x1a8):main.cpp: first defined here
Zeit.o(.text+0x100):Zeit.cpp: multiple definition of `Zeit::Zeit()'
main.o(.text+0x100):main.cpp: first defined here
Zeit.o(.text+0x12c):Zeit.cpp: multiple definition of `Zeit::Zeit()'
main.o(.text+0x12c):main.cpp: first defined here
Zeit.o(.text+0x158):Zeit.cpp: multiple definition of `Zeit::Zeit(int, int, int)'
main.o(.text+0x158):main.cpp: first defined here
Zeit.o(.text+0x180):Zeit.cpp: multiple definition of `Zeit::Zeit(int, int, int)'
main.o(.text+0x180):main.cpp: first defined here
Zeit.o(.text+0x1c8):Zeit.cpp: multiple definition of `Zeit::getZeit()'
main.o(.text+0x1c8):main.cpp: first defined here
Zeit.o(.text+0x1f6):Zeit.cpp: multiple definition of `Zeit::IntToString(int)'
main.o(.text+0x1f6):main.cpp: first defined here
Zeit.o(.text+0x1a8):Zeit.cpp: multiple definition of `Zeit::setZeit(int, int, int)'
main.o(.text+0x1a8):main.cpp: first defined here
collect2: ld returned 1 exit status

make.exe: *** [psta2.exe] Error 1

Execution terminated
Evtl. kann mir ja ein C++-Profi etwas weiterhelfen. Ich benutze übrigens Dev-C++, falls das irgendwas am Sachverhalt ändert ;)

PlaciD
 
Hi!
Ich denke zwar nicht, dass die folgenden Beanstandungen den Kohl fett gemacht haben, aber immerhin =).

z.B:

Zeit::Zeit(void){
setZeit(0,0,0);
} ////////// BITTE ohne Semikolon

// Defaultkonstruktor
Zeit(); // Void brauchst auch net ;)


vielleicht hilft auch das^^

#ifdef __DEINENHEADER_H__
#define __DEINENHEADER_H__

und am Ende vom Quelltext

#endif


Naja, der Profi bin ich aber auch net, hoffe aber das es was nüzt ^^
 
Ich wuerd gern mal deine anderen 3 Datein sehen, du definierst deine Zeit Klasse irgendwie "komisch" - genauer kann ichs leider ohne mehr Code nicht sagen :-?
 
Hi,

habs jetzt erstmal dadurch gelöst, dass das jetzt alles header-Dateien sind. Sobald ich die nämlich als .cpp speichere und include, gehts nimmer.

Auch das ifdef nutzt irgendwie nicht.

Danke euch beiden trotzdem!

PlaciD
 
Zeit.h:
Code:
#ifndef ZEIT_H
#define ZEIT_H
class Zeit {
    
    private:
        int stunden;
        int minuten;
        int sekunden;
        string IntToString(int i);
    
    public:
        // Defaultkonstruktor
        Zeit(void);
        //normaler Konstruktor
        Zeit(int std, int min, int sec);
        
        void setZeit(int std, int min, int sec);
        string getZeit();
        
};
#endif
Zeit.cpp
Code:
#include <string>
#include <sstream>
#include "zeit.h"
using namespace std;

Zeit::Zeit(void){
    setZeit(0,0,0);
};

Zeit::Zeit(int std, int min, int sec){
    setZeit(std,min,sec);
};

void Zeit::setZeit(int std, int min, int sec){
    stunden = std;
    minuten = min;
    sekunden = sec;
};

string Zeit::getZeit(){
    return(IntToString(stunden));
};

/* METHODE kopiert und modifziert von 
 * https://fara.cs.uni-potsdam.de/%7Ekaufmann/?page=GenCppFaqs&faq=IntToString#Answ
 */
string Zeit::IntToString(int i){
    ostringstream temp;
    temp << i;
    
    return(temp.str());
};

Zu deinem Fehler: du verwendest die Klasse anscheinend mehrere male und da die Header und Implementierung bei dir in ein und der selben Datei und ohne #ifndef stehen wird die Klasse jedes mal neu deklariert und daher die Fehlermeldung das die Klasse schon bekannt ist.
 
Zu deinem Fehler: du verwendest die Klasse anscheinend mehrere male und da die Header und Implementierung bei dir in ein und der selben Datei und ohne #ifndef stehen wird die Klasse jedes mal neu deklariert und daher die Fehlermeldung das die Klasse schon bekannt ist.

Ganz genau das habe ich eben nicht, das war ja irgendwie das Problem.

Ich hatte folgenden Aufbau:

main.cpp => imports laeufer.cpp => imports zeit.cpp,geschlecht.cpp,verein.cpp

Ansonsten immer nur <string>, <iostream> usw. importiert. Ja, und zack kam immer der Fehler :-?

Nun habe ich aber noch zwei Fragen:
Ich steig bei dem ganzen .cpp und .h-Dateien noch nicht durch. Was nimmt man den nun für was her?
Und wie schaffe ich es, dass ich in der laeufer.h ein Objekt vom Typ Verein referenzieren kann und gleichzeitig in der verein.h ein Objekt vom Typ laeufer. In Java läuft das ja alles über packages. Da kennt jede Klasse jede Klasse aus dem package. Bei C++ scheint das nicht so zu klappen, jedenfalls habe ich noch keinen Weg gefunden.

PlaciD
 
Du musst der jeweilig anderen die Headerdatei der anderen Klassse includen,d abei darf aber das #ifndef nicht fehlen da das ganze sonst im Kreis läuft.
 
Noch mal ne kleine Zusammenfassung, die auch deine Frage erfüllen(bestimmt weißt du aber schon das Meiste xD) sollte^^

Wichtig:
Die .h und die .cpp sollten den gleichen Namen tragen,
den deiner Klasse. Und immer die Header-Datei in die CPP-Datei includieren.

In die .h:
In die .h gehört NUR das Gerippe deiner Klasse rein.

z.B:
Code:
class Beispiel
{
private:
 int i;

public: 
 Beispiel();
};

Also in die .cpp:
Hier kommen deine Implementierungen rein, also
Quelltext der Methoden und Konstuktoren/Destruktoren deiner Klasse.

z.B:

Code:
Beispiel::Beispiel()
{
i = i + 1;
}

Zudem würde ich sicherheitshalber in jeder Headerdatei folgendes einfügen:

Am Quelltextanfang
Code:
#ifndef __DEINHEADER__H 
#define __DEINHEADER__H

Am Ende des Quelltextes
Code:
#endif
 
Zuletzt bearbeitet:
warum machst du


gehört da nicht <iostream> ?
oder is das eh richtig so?

hab c++ vor nem jahr in der schule gelernt, aber an ein sstream kann ich mich net erinnern...

sstream steht für stringstream, das ist ne klasse die dir hilft zahlen und andere dinge in strings umzuwandeln.
 
sstream steht für stringstream, das ist ne klasse die dir hilft zahlen und andere dinge in strings umzuwandeln.

Ganz genau, bei der Zeit-Klasse wandle ich die Zeit dann in nen String um, den sich andere Klassen per getter holen können.

@Yokuhono: Danke für deine Zusammenfassung. So genau kannte ich mich da noch nicht aus. In Java ist das alles viel schöner :-? Aber egal, da muss ich jetzt durch. Mal sehen, ob ich das heute irgendwie hinbekomme, sonst melde ich mich nochmal!

Danke allen, die geholfen haben!

PlaciD
 
Zudem würde ich sicherheitshalber in jeder Headerdatei folgendes einfügen:
Am Quelltextanfang
Code:
#ifndef __DEINHEADER__H 
#define __DEINHEADER__H
Am Ende des Quelltextes
Code:
#endif
Das hat mir mein Prof. damals als Include-Wächter vorgestellt. Und bei Programmen, die aus mehr als 2 Dateien bestehen, ist das Ding die absolute Pflicht! Insbesondere, wenn der Header Klassendefinitionen enthält.

Nun habe ich aber noch zwei Fragen:
Ich steig bei dem ganzen .cpp und .h-Dateien noch nicht durch. Was nimmt man den nun für was her?
Generell treten *.h und *.cpp Dateien nur in Pärchen auf. Die *.h enthält dabei Deklarationen von Funktionen / Klassen
PHP:
double max(double dIn1, double dIn2); // Deklaration einer Funktion
class CZeit; // Deklaration einer Klasse
class CLaeufer; // Deklaration einer zweiten Klasse
oder Klassendefinitionen
PHP:
class CZeit // Definition einer Klasse
{
public:
CZeit(void); // Deklaration einer Methode
...
};
Während die *.cpp die Definitionen der Funktionen und Methoden enthält:
PHP:
// Definition einer Funktion
double max(double dIn1, double dIn2)
{
if(dIn1>dIn2) { retrun dIn1; }
return dIn2;
}
// Definition einer Methode
CZeit::CZeit(void)
{
// Mache irgendetwas!
}

Wenn du also eine Klasse CZeit erstellst, dann (deklarierst und) definierst du diese Klasse im Header CZeit.h. In der Quellcode-Datei CZeit.cpp bindest du dann den Header ein (#include "CZeit.h") und definierst danach die Methoden. Und überall, wo diese Klasse benutzen möchtest, bindest du NUR den Header ein.
Und wie schaffe ich es, dass ich in der laeufer.h ein Objekt vom Typ Verein referenzieren kann und gleichzeitig in der verein.h ein Objekt vom Typ laeufer. In Java läuft das ja alles über packages. Da kennt jede Klasse jede Klasse aus dem package. Bei C++ scheint das nicht so zu klappen, jedenfalls habe ich noch keinen Weg gefunden.
Das Problem ist, dass ein Objekt nur benutzt werden kann, wenn seine Klasse vorher definiert wurde. Um die Klasse Verein zu definieren muss also die Klasse Laeufer bereits definiert sein, was aber wiederum voraussetzt, dass die Klasse Verein schon definiert wurde. Das funktioniert so nicht!

Was aber funktioniert ist die Verwendung von Pointern! Schreibe die beiden Klassen einfach so, dass sie anstatt eines Objekts der jeweils anderen Klasse nur einen Pointer auf eben diese enthalten. Um einen Pointer auf die Klasse Verein zu verwenden, ist nämlich keine komplette Definition der Klasse Verein nötig, sondern es reicht eine einfache Deklaration.
PHP:
// Datei: Verein.h
// Dieser Include-Wächter verhindert, dass dieser Header erneut
// durch "Laeufer.h" eingebunden wird.
#ifndef _LAEUFER_H_
#define _LAEUFER_H_
#include "Laeufer.h" // Klasse Laeufer "einbinden"
class Laeufer; // Die Klasse Laefer deklarieren, damit wir einen Pointer auf sie setzen können.
class Verein
{
...
private:
Laeufer* m_pLaeufer;
...
};
#endif
PHP:
// Datei: Verein.cpp
#include "Verein.h" // Klassendefinition einbinden
// Konstruktor
Verein::Verein(void)
{
// Ein Laeufer Objekt erstellen.
m_pLaeufer = new Laeufer;
}
// Destruktor
Verein::~Verein(void)
{
// Das Objekt wieder loeschen.
If( m_pLaeufer ) { delete m_pLaeufer; }
}

Wenn man weiß, wie's geht, ist C++ richtig super!

MfG
Sven
 
Hi,

erstmal Danke :)

Nun bin ich aber tatsächlich zu dämlich, das hinzubekommen :-?

Also, ich habe jetzt alles mal in die main.cpp gepackt, nur um zu sehen, ob es wenigstens theoretisch funktioniert. Und siehe da, es geht (bis auf nen Fehler wegen Konvertierung von int zu string, aber da arbeite ich dran.

Ich poste die Klasse jetzt einfach mal und wäre unheimlich dankbar, wenn mir die jemand so zerlegen könnte, dass es auch mit .h und .cpp Dateien (also ordentlich getrennt, jede Klasse in 2 Dateien) funktioniert.

Code:
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

string IntToString(int i);

#ifndef GESCHLECHT_H
#define GESCHLECHT_H

enum Geschlecht{
    weiblich=0,
    maennlich=1
};

#endif

#ifndef ZEIT_H
#define ZEIT_H

class Zeit {

    private:
        int stunden;
        int minuten;
        int sekunden;

    public:
        // Defaultkonstruktor
        Zeit();
        //normaler Konstruktor
        Zeit(int std, int min, int sec);

        void setZeit(int std, int min, int sec);
        string getZeit();

};

#endif

#ifndef VEREIN_H
#define VEREIN_H

class Verein {

    private:
        string name;

    public:
        // Defaultkonstruktor
        Verein();
        //normaler Konstruktor
        Verein(string name_);

};

#endif

#ifndef LAEUFER_H
#define LAEUFER_H

class Laeufer{

    private:
        int startnummer;
        string vorname;
        string nachname;
        int alter;
        Geschlecht geschlecht;
        Zeit laufzeit;
        Verein verein;

    public:
        Laeufer(int startnummer_,string vorname_,string nachname_, int alter_,Geschlecht geschlecht_,Zeit laufzeit_,Verein verein_);
        string getDatenstring();
        int getStartnummer();
        string getVorname();
        string getNachname();
        int getAlter();
        Geschlecht getGeschlecht();
        Zeit getLaufzeit();
        Verein getVerein();
};

#endif

Zeit::Zeit(void){
    setZeit(0,0,0);
}

Zeit::Zeit(int std, int min, int sec){
    setZeit(std,min,sec);
}

void Zeit::setZeit(int std, int min, int sec){
    stunden = std;
    minuten = min;
    sekunden = sec;
}

string Zeit::getZeit(){
    return(IntToString(stunden));
}

Verein::Verein(){
    //do nothing
}

Verein::Verein(string name_){
    name = name_;
}

Laeufer::Laeufer(int startnummer_,string vorname_,string nachname_, int alter_,Geschlecht geschlecht_,Zeit laufzeit_,Verein verein_){
    startnummer = startnummer_;
    vorname = vorname_;
    nachname = nachname_;
    alter = alter_;
    geschlecht = geschlecht_;
    laufzeit = laufzeit_;
    verein = verein_;
}

string Laeufer::getDatenstring(){
    string ret = " ";
    return ret;
}

int Laeufer::getStartnummer(){
    return startnummer;
}

string Laeufer::getVorname(){
    return vorname;
}

string Laeufer::getNachname(){
    return nachname;
}

int Laeufer::getAlter(){
    return alter;
}

Geschlecht Laeufer::getGeschlecht(){
    return geschlecht;
}

Zeit Laeufer::getLaufzeit(){
    return laufzeit;
}

Verein Laeufer::getVerein(){
    return verein;
}

/* METHODE kopiert und modifziert von
 * https://fara.cs.uni-potsdam.de/%7Ekaufmann/?page=GenCppFaqs&faq=IntToString#Answ
 */
string IntToString(int i){
    ostringstream temp;
    temp << i;

    return(temp.str());
}

int main()
{

}

Vielen Dank schonmal,
Sebastian
 
Dieser Code-Tag is ja grauselig. Das hat richtig Nerven gekostet das Gestrüp zu entfitzen... (oder werden nur bei mir keine Zeilenumbrüche angezeigt?)

Hab mich jedenfalls mal, warum auch immer :mrgreen:, drangemacht und die das alles aufgesplittet. Kann ich dir das auch zuschicken?

zeit.h

PHP:
#ifndef ZEIT_H
#define ZEIT_H
#include <string>
using namespace std;
class Zeit
{
     private:
          int stunden;
          int minuten;
          int sekunden;
     public:
         Zeit();// Defaultkonstruktor
         Zeit(int std, int min, int sec); //normaler Konstruktor
         void setZeit(int std, int min, int sec);
         string getZeit();
};
#endif

verein.h

PHP:
#ifndef VEREIN_H
#define VEREIN_H
#include <string>
using namespace std;
class Verein
{
      private:
         string name;
      public:
         Verein(); // Defaultkonstruktor
         Verein(string name_);//normaler Konstruktor
};
#endif


laeufer.h

PHP:
#ifndef LAEUFER_H
#define LAEUFER_H
#include <string>
#include "sonstig.h"
#include "verein.h"
#include "zeit.h"
class Laeufer
{
      private:
         int startnummer;
         string vorname;
         string nachname;
         int alter;
         Geschlecht geschlecht;
         Zeit laufzeit;
         Verein verein;
      public:
          Laeufer(int startnummer_,string vorname_,string nachname_, int alter_,Geschlecht geschlecht_,Zeit laufzeit_,Verein verein_);
          string getDatenstring();
          int getStartnummer();
          string getVorname();
          string getNachname();
          int getAlter();
          Geschlecht getGeschlecht();
          Zeit getLaufzeit();
          Verein getVerein();
};
#endif

sonstig.h

PHP:
#include <string>
using namespace std;
string IntToString(int i);
#ifndef GESCHLECHT_H
#define GESCHLECHT_H
   enum Geschlecht{ weiblich=0, maennlich=1 };
#endif

zeit.cpp

PHP:
#include "zeit.h"
#include "sonstig.h"
Zeit::Zeit(void)
{
    setZeit(0,0,0);
}
Zeit::Zeit(int std, int min, int sec)
{
    setZeit(std,min,sec);
}
void Zeit::setZeit(int std, int min, int sec)
{
     stunden = std; minuten = min; sekunden = sec;
}
string Zeit::getZeit()
{
     return(IntToString(stunden));
}

verein.cpp

PHP:
#include "verein.h"
Verein::Verein()
{ //do nothing
}
Verein::Verein(string name_)
{
    name = name_;
}

laeufer.cpp
PHP:
#include "laeufer.h"
Laeufer::Laeufer(int startnummer_,string vorname_,string nachname_, int alter_,Geschlecht geschlecht_,Zeit laufzeit_,Verein verein_)
{
     startnummer = startnummer_;
     vorname = vorname_;
     nachname = nachname_;
     alter = alter_;
     geschlecht = geschlecht_;
     laufzeit = laufzeit_;
     verein = verein_;
}
string Laeufer::getDatenstring()
{
    string ret = " ";
    return ret;
}
int Laeufer::getStartnummer()
{
     return startnummer;
}
string Laeufer::getVorname()
{
     return vorname;
}
string Laeufer::getNachname()
{
     return nachname;
}
int Laeufer::getAlter()
{
    return alter;
}
Geschlecht Laeufer::getGeschlecht()
{
    return geschlecht;
}
Zeit Laeufer::getLaufzeit()
{
    return laufzeit;
}
Verein Laeufer::getVerein()
{
    return verein;
}

sonstig.cpp
PHP:
#include <sstream>
#include "sonstig.h"
/* METHODE kopiert und modifziert von * https://fara.cs.uni-potsdam.de/%7Ekaufmann/?page=GenCppFaqs&faq=IntToString#Answ */
string IntToString(int i)
{
    ostringstream temp;
    temp << i;
    return(temp.str());
}
 
Zuletzt bearbeitet:
Hey Robert,

vielen lieben Dank, sehr freundlich von dir. Zuschicken ist eigentlich nicht nötig, ist besser wenn es manuell rauskopiere und drüber nachdenke ;)

Der Code wird bei mir übrigens schön Zeile für Zeile angezeigt, fast so wie im Editor...

So, dann hoffe ich mal, mir wird jetzt einiges etwas klarer. Muss am 15. das Programm abgeben :mrgreen:

Danke nochmal,
Sebastian