Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

14.05.2011, 12:49

Vererbung und Includes - Verwirrung

Hallo,

da in dem Buch bis Kapitel 8 alles in einer Datei steht ( der übersicht halber ) wollte ich heute früh mal ein gut strukturiertes Beispiel schreiben. Dabei bin ich jetzt etwas verwirrt und ich hoffe ihr könnt die Sache erklären.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//CRaumschiff - Interface

class CRaumschiff{
public:
    CRaumschiff();
    CRaumschiff(int xPos, int yPos);
    ~CRaumschiff();

private:
    int m_yPos;
    int m_xPos;
    int m_Energie;
    float m_fGeschwindigkeit;
};

//CRaumschiff.cpp
#include <iostream>
#include "CRaumschiff.h"


using namespace std;

//Konstruktor
CRaumschiff::CRaumschiff() {
    m_Energie = 1000;
    m_xPos = NULL;
    m_yPos = NULL;
    m_fGeschwindigkeit = NULL;
}

//Konstruktor
CRaumschiff::CRaumschiff(int xPos, int yPos) {
    
    //Initialisierung
    //Pos pruefen
    if(xPos >= 0 && xPos <= 800 && yPos >= 0 && yPos <= 600) 
    {
        cout << "Gueltige Koordinaten" << endl;
        m_xPos = xPos;
        m_yPos = yPos;
    }
    else 
    {
        cout << "Ungueltige Koordinaten fuer Raumschiff" << endl;
        m_xPos = 0;
        m_yPos = 0;
    }
    m_Energie = 1000;
    m_fGeschwindigkeit = NULL;

    
}

//Destruktor 
CRaumschiff::~CRaumschiff() {
    cout << "Ausgabe von Destruktor";
}


//CHunter Interface
class CHunter :
    public CRaumschiff
{
public:
    CHunter(void);
    ~CHunter(void);
    void angriff();
};


//CHunter.cpp
#include <iostream>
#include "CHunter.h"


using namespace std;

CHunter::CHunter(void)
{
    cout << "Start Hunter"; 
}

void CHunter::angriff(void) {
    cout << "Angriff!!!";
}

CHunter::~CHunter(void)
{
    cout << "Zerstoere Hunter!";
}

//MAIN
#include <iostream>

using namespace std;

#include "CRaumschiff.h"
#include "CHunter.h"





//Hauptprogramm
int main() {
    CRaumschiff *pPilot = NULL;
    CRaumschiff *pGegner = NULL;
    CRaumschiff *pHunter = NULL;

    int xPos, yPos;

    cout << "Y-Pos von Gegner:";
    cin >> yPos;
    cout << "X-Pos von Gegner:";
    cin >> xPos;

    pPilot = new CRaumschiff[10]();
    pGegner = new CRaumschiff();
    pHunter = new CHunter();
    

    //Raumschiff zerstören
    delete[] pPilot;
    pPilot = NULL;

    delete pGegner;
    pGegner = NULL;

    delete pHunter;
    pHunter = NULL;

    cin >> yPos;

    return 0;

}


Er wirft mir nun vor, er würde die Klasse CRaumschiff bei der Vererbung in CHunter nicht kennen! Aber in der Main Methode include ich doch zuerst die CRaumschiff und danach die CHunter. Demzufolge sollte er sie doch kennen ?!?!
Wenn ich nun ein include "CRaumschiff.h" in die CHunter.h schreibe und den include "CRaumschiff.h" aus der MAIN lösche, funktioniert alles super.
Das kommt mir aber sehr sehr unlogisch vor.

Wäre super wenn mir jemand helfen kann, oder mir das ganze erklären kann.

LG
Sebastian

Fred

Supermoderator

Beiträge: 2 121

Beruf: Softwareentwickler

  • Private Nachricht senden

2

14.05.2011, 13:06

Das Problem liegt an CHunter.cpp. Denn dort inkludierst du nur CHunter.h, aber nicht CRaumschif.h. Daher kennt er dann logischerweise auch CRaumschiff nicht. Eine Möglichkeit ist es nun beispielsweise die Include-Anweisung in den Header zu packen, dann, musst du nicht darauf achten, dass andere Dateien, die diese Klasse verwenden wollen, diese auch einbinden müssen.
Oder aber du bindest eben immer, wenn du CHunter.h inkludierst auch CRaumschiff.h ein.

3

14.05.2011, 13:23

Eine Möglichkeit ist es nun beispielsweise die Include-Anweisung in den Header zu packen
Möglichkeit? Ich behaupte mal ganz frech das alles andere eine Zumutung wäre.

4

14.05.2011, 13:58

Eine Möglichkeit ist es nun beispielsweise die Include-Anweisung in den Header zu packen



In welchen header? Kannst du mir ein Beispiel geben ?

lg

Fred

Supermoderator

Beiträge: 2 121

Beruf: Softwareentwickler

  • Private Nachricht senden

5

14.05.2011, 14:13

CHunter.h

C-/C++-Quelltext

1
2
3
4
5
6
#include "CRaumschiff.h"

class CHunter : public CRaumschiff
{
    //...
};


Müsste egtl. genau das sein, was nach deiner Beschreibung bei dir schon funktioniert hat ;)

6

14.05.2011, 14:20

Ja ok,

aber dann find ich es super verwirrend. Denn ich habe dann lediglich ein include in meiner main.cpp:

#include "CHunter.h"

Ist das wirklich eine "saubere" Lösung ? Ich muss dann lediglich die Kindklasse includen um die CRaumschiff zu inkluden.

Würde ich nun als Außenstehender sagen:
Ich möchte die CRaumschiff.h und die CHunter.h verwenden würde ich folgendes inkluden:

#include "CRaumschiff.h"
#include "CHunter.h"

Leider wirft er ja dann hier ein Fehler, da ein inklude auf CRaumschiff schon in der CHunter.h statt findet.

Wie die siehst bin ich immernoch etwas verwirrt ^^

Fred

Supermoderator

Beiträge: 2 121

Beruf: Softwareentwickler

  • Private Nachricht senden

7

14.05.2011, 14:44

Ja das habe ich ja oben schon beschrieben. Da gibt es eben zwei Ansätze. Den ersten, den Cubic sehr deutlich präferriert ;) und den auch ich bevorzuge.
Dieser inkludiert innerhalb der Header-Datei alles, was benötigt wird. Ziel ist dabei die Benutzung einer Klasse möglichst einfach zu machen. Der Nutzer muss sich eben nicht Gedanken darüber machen, welche Dateien er alles brauchen könnte, weil sie die gewünschte Klasse verwenden möchte, sondern inkludiert einfach bspw. "CHunter.h" und den Rest übernimmt die Header-Datei. Wie das aussähe habe ich ja oben verdeutlicht.

Die Alternative hierzu wäre, dass der Nutzer selbst alles einbinden muss, was benötigt wird. Und das überall, wo es benötigt wird.
In deiner main.cpp bindest du bspw. CRaumschiff und CHunter ein, aber in deiner CHunter.cpp inkludierst du nur CHunter und da liegt der Hund begraben, denn an dieser Stelle benötigst du ebenfalls CRaumschiff, also muss es auch dort inkludiert werden.
Im Code sähe das dann so aus:
CHunter.h:

C-/C++-Quelltext

1
2
3
4
class CHunter : public CRaumschiff
{
//...
};

CHunter.cpp

C-/C++-Quelltext

1
2
3
#include "CRaumschiff.h"
#include "CHunter.h"
//...

Main.cpp

C-/C++-Quelltext

1
2
3
#include "CRaumschiff.h
#include "CHunter.h"
//...

Aller andere Dateien, die Hunter verwenden wollen müssen ebenfalls beide Dateien einbinden.

8

14.05.2011, 15:11

Ja das habe ich ja oben schon beschrieben. Da gibt es eben zwei Ansätze. Den ersten, den Cubic sehr deutlich präferriert und den auch ich bevorzuge.
Dieser inkludiert innerhalb der Header-Datei alles, was benötigt wird. Ziel ist dabei die Benutzung einer Klasse möglichst einfach zu machen. Der Nutzer muss sich eben nicht Gedanken darüber machen, welche Dateien er alles brauchen könnte, weil sie die gewünschte Klasse verwenden möchte, sondern inkludiert einfach bspw. "CHunter.h" und den Rest übernimmt die Header-Datei. Wie das aussähe habe ich ja oben verdeutlicht.



So richtig 100% ist mir das noch nicht klar. Ich versuch es nochmal mit ein paar Beispiele:

Zuerst stell ich die Variante vor, die du beschrieben hast und du als beste möglichkeit darstellt. Wenn ich da schon ein Fehler habe geb mir bescheid ;p

C-/C++-Quelltext

1
2
3
//main.cpp#include "CHunter.cpp"
//CHunter.h#include "CRaumschiff.h" /* benötigt man damit die Vererbung klappt */
//CRaumschiff.h//kein Include


Somit ergibt sich eine Inklude von: CRaumschiff -> CHunter -> main

Jetzt stellt sich für mich die Frage, was passiert wenn ich eine weitere Klasse hinzufüge.

Nach diesem von mir verstandenen Schema käme jetzt folgendes hinzu:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//CDrone Interface
#include "CRaumschiff.h"
class CDrone :
    public CRaumschiff
{
public:
    CDrone(void);
    ~CDrone(void);
    void spioniere();
};


//CDrone.cpp
#include <iostream>
#include "CDrone.h"


using namespace std;

CDrone::CDrone(void)
{
    cout << "Start Drone"; 
}

void CDrone::spioniere(void) {
    cout << "spioniere";
}

CDrone::~CDrone(void)
{
    cout << "Zerstoere Drone!";
}

Jetzt geht aber alles in die Hose... der kompiler wirft Fehler über Fehler was auch irgendwie klar ist.

Ich inklude nun ja 2 mal die CRaumschiff.h da ich sie in der CDrone.h und CHunter.h inklude.

Wäre super wenn du mir mit Hilfe von 2 Kindelementen das ganze nochmal sauber zeigt :p

LG

PS: Sorry das ich anscheinend scher von begriff bin... es ist jedoch sehr wichtig das ganze 100% zu verstehen.

LG
Sebastian

Fred

Supermoderator

Beiträge: 2 121

Beruf: Softwareentwickler

  • Private Nachricht senden

9

14.05.2011, 15:42

Also zunächst mal musst du natürlich in der Datei CHunter.cpp ebenfalls "CHunter.h" inkludieren.
Denn Cpp Dateien agieren weitgehend unabhängig voneinander. Nur weil du in "Main.cpp" "CHunter.h" einbindest, kennt es "CHunter.cpp" noch lange nicht.
Um das Problem mit den mehrfachen Includes zu verhindern musst du Include Guards verwenden.
In einem Beispiel sähe das so aus:

CRaumschiff.h

C-/C++-Quelltext

1
2
3
4
5
6
7
#ifndef CRAUMSCHIFF_H
#define CRAUMSCHIFF_H
class CRaumschiff
{
// ...
};
#endif


CHunter.h

C-/C++-Quelltext

1
2
3
4
5
6
7
8
#ifndef CHUNTER_H
#define CHUNTER_H
#include "CRaumschiff.h"
class CHunter : public CRaumschiff
{
// ...
};
#endif


Main.cpp

C-/C++-Quelltext

1
2
#include "CHunter.h"
//...


CHunter.cpp

C-/C++-Quelltext

1
2
#include "CHunter.h"
//...


So wird jede Include-Datei nur einmal geladen und es gibt keine Probleme mit multiplen Includes.

10

14.05.2011, 15:48

Ok nun macht alles Sinn!
Es bilden sich also folgende Regeln:


1. Alle Klassen welche von einer anderen Klasse etwas erben inkludieren die Headerdatei der Elternklasse in ihrer Headerdatei.
2. Alle Klassen von denen ggf. gerbt werden kann, müssen inklude Guards verwenden.

Ich denke das Thema kommt im Buch wirklich zu kurz, oder falls es später behandelt wird, sollte daraufhin gewiesen werden. :) So als kleinen Tip an den Author.

Danke vielmals für deine Unterstützung.

LG
Sebastian

Werbeanzeige