# C++ und die tollen Klassen



## AMD (19. April 2011)

Hey Leute,

Ich tue mich seeeeeehr schwer mit dem Thema Klassen und hoffe hier kann mir jmd. weiterhelfen!
ich habe schon gefühlte 100 Anleitungen gegoogelt sowie mehrere Videos auf YouTube dazu geguckt aber der Funken will wohl nicht überspringen!

Eig. kann ich programmieren aber ich gehöre wohl eher zu den "struct" Leuten 

Die Sache ist, ich muss für ein Modul in der Uni Objekt Orientiere Programmierung machen wodurch das nunmal rein muss!
Aber okay, nochmal genau was ich will (gerne von euch hätte wohl eher)^^

- Vllt. mal eine Simple Klasse, z.B. sowas:



> class Soldat {
> public: void SetLeben(int x);
> int GetLeben();
> 
> ...


Also ich möchte 1mal mit SetLeben den int leben ändern bzw. mit Get den aktuellen Wert abfragen... leider wenn ich das probiere sagt der compiler: Vergiss es 

wäre also schön wenn, die funktion (bzw. methode) von GetLeben einen return Wert gibt.
Also ich schreibe in der Main: int wtf = GetLeben(); und bekomme dann den Wert von leben in wtf. (Habe mal eine genauere Bezeichnung vor GetLeben weggelassen).

Außerdem wüsste ich noch gern folgendes:
Wann nimmt man: "::", "->" und "."

Hoffe es ist einigermaßen Verständlich und man kann mir weiterhelfen ^^


----------



## -Phoenix- (19. April 2011)

Moin 

ja was sagt den der Compiler?
du musst ja erstmal nen neues Objekt aus deiner Klasse Soldat erstellen . Und die Methode dann mit Objektname.Methodenname() aufrufen.

lg.


----------



## zcei (19. April 2011)

Hab ich was verpasst, hat c++ ne neue Sprache eingefuehrt?

Ich dachte immer es heisst "public" und "private"


----------



## AMD (19. April 2011)

zcei schrieb:


> Hab ich was verpasst, hat c++ ne neue Sprache eingefuehrt?
> 
> Ich dachte immer es heisst "public" und "private"


 
ups... passiert... heißt natürlich public und nicht puplic 

Der Compiler sagt viel, hab ja mehrere Dinge probiert wodurch es zu vielen Fehler kommt...
Kann mir einer nicht mal zeigen wie am besten dieses GetLeben() geht mit return?


----------



## xEbo (19. April 2011)

:: für Klasseninterne Funktionen.
-> für Zugriffe auf dynamische Objekte (new Object)
. für Zugriff auf Objektfunktionen.

also:

Erst einmal musst du deine Funktionen in deinem Code definieren:

Soldat::Setleben(int x){
leben = x;
return;
}

Soldat::Getleben(){
return leben;
}

dann iwo in der main:

{
...
Soldat Soldat;
Soldat.Setleben(50);
cout<<Soldat.Getleben;

oder so ähnlich, ist auch schon ewig her dass ich was programmiert habe. Alternativ kannst für die Klassenfunktionen auch this->leben nehmen. Sollte aber auch ohne funktionieren.

Zum Code: Objekt Soldat erzeugen. Leben setzen. Leben nachschauen. 
Zugriffe auf private Variablen ist nur über Funktionen möglich. Daher auch die Set und Get Methoden. Ein direkter Zugriff ist daher nicht möglich.


----------



## Bauer87 (19. April 2011)

… und nicht zu vergessen, das Semikolon nach der Klassendefinition:


```
class foo{
public:
    bar();
}[B];[/B]
```


----------



## Freddycbv (20. April 2011)

Der Fehler liegt hier:


```
class Soldat 
{
public: 
void SetLeben(int x);
int GetLeben();
 
[B]private: int leben = 100;[/B]
}
```
Variablen darf/kann man nicht schon in der Klassendefinition einen Wert geben, das geschieht im _Konstruktor_ einer Klasse,
aber erstmal ganz von vorne:

Also, Klassen sind eigentlich kein Hexenwerk:

In der Praxis sieht das so aus:

 Sie haben ihre Klasse in einer Haeder-Datei, also hier zum Beispiel in Soldat.h:

```
//Soldat.h

class Soldat 
{
     public:
     [I]Soldat();[/I] 
     void SetLeben(int x);
     int GetLeben();
 
     private: 
     int leben;
};
```
In dieser Klasse haben sie also ihre Klassenfunktionen(public) und ihre Variablen(private) sowie den _Konstruktor Soldat()_. Der Konstruktor einer Klasse wird immer dann aufgerufen, wenn man ein Objekt dieser Klasse erstellt, und er hat den Sinn Variablen ihren Wert zuzuweisen. Ein Konstruktor hat keinen return Wert, auch nicht void!!.

OK, weiter im Code:

Die Klassenfunktionen und der Konstruktor liegen zusammen mit main() in einer zweiten Datei, zB MeinProgramm.cpp 

```
//MeinProgramm.cpp

#include <iostream>
#include "Soldat.h" // Wichtig
using namespace std;


Soldat::Soldat() //Konstruktor
{
    leben=100; //Weist Leben den Wert 100 zu, wenn ein Objekt vom Typ Soldat erstellt wird
}

void Soldat::SetLeben(int x)
{
    leben=x;
}

int Soldat::GetLeben()
{
    return leben;
}

//  und schließlich das Programm

int main(void)
{
    Soldat Testsoldat; // Erzeugt ein Objekt Testsoldat vom Typ Soldat, hierbei wird der Konstruktor aufgerufen
    cout << Soldat.GetLeben() << endl ; // sollte 100 anzeigen
    Soldat.SetLeben(36);
    cout << Soldat.GetLeben() << endl ; // sollte 36 anzeigen
    return 0;
}
```
Das Programm sollte funktionieren, ich habs aber nicht getestet.
Ok, zu '.' , '::' und '->' :

Beim definieren der Funktionen einer Klasse weiß der Compiler nicht, zu wem die Funktionen gehören weshalb hier vor den Funktionsnamen die Klasse geschrieben wird, und dazwischen der berüchtigte '::' Punkt ,also z.B so:
void Klasse*::*Klassenfunktion() {...}

Wenn man nun die Funktion oder Variable eines _Objektes_ benutzen will, wird der Punkt benutzt, also z.B so:

```
int main(void)
{
    Klasse KlassenObjekt; 
    KlassenObjekt.Klassenfunktion(); 
    return 0;
}
```
Hat man dagegen einen Zeiger auf ein Objekt, benutzt man -> um auf dessen Funktionen zuzugreifen, also z.B so:

```
int main(void)
{
    Klasse KlassenObjekt; 
    Klasse * ZeigerAufObjekt = &KlassenObjekt; 
    ZeigerAufObjekt->Klassenfunktion(); 
    return 0;
}
```
Ok, das wars eigentlich , 
hoffe das kann man einigermaßen verstehen

Freddycbv


----------



## Bauer87 (20. April 2011)

… und ich hatte das als Typo hier im Forum gesehen. Kann man in der Definition eines Structs werte zuweisen? Darauf wäre ich nur bei Konstanten gekommen.


----------



## KingofKingzZ (20. April 2011)

Freddycbv hat eigentlich schon alles schön erklärt, allerdings sollte man Zuweisungen im Konstruktor in der Initialisierungsliste machen:


```
Soldat::Soldat() : leben (100)
{}
```

Und falls du in der Klasse etwas mit new anlegst, vergiss nicht es spätestens im Destruktor wieder freizugeben. 

```
Soldat::~Soldat () 
{ 
     // aufräumen
}
```


struct und class sind in C++ übrigens *exakt* das gleiche, nur dass bei struct standardmäßig alles public ist und bei class standardmäßig alles private. 

lg


----------



## Freddycbv (27. April 2011)

Ich war über Ostern weg, sonst hätt ich früher gefragt,
Warum sollte man Zuweisungen im Konstruktor machen??
Hat das nicht die selbe Wirkung wie IM Konstruktor??

Auch habe ich beim Destruktor immer das Problem, dass ,wenn ich zum Beispiel den Speicherplatz für leben in der Klasse Soldat im Konstruktor mit new 
anfordere, und im Destruktor wieder freigebe, "Speicherlöcher" entstehen . Wenn ich zum Beispiel solch ein Code habe:

```
int main(void)
{
    Soldat Offizier;
    NutzloseFunktion(&Offizier);
    Offizier.GetLeben();
}

void NutzloseFunktion(Soldat * Zeiger)
{
    Soldat Test;
    Test.SetLeben(39);
    // und vielleicht noch weitere Anweisungen
    Zeiger = &Test;
    // leben von Test wird im Destruktor freigegeben
}
```
Crash, BAMM, B U M M 
leben wurde in dem Destruktor von Test aufgeräumt, und in main kann ich nicht mehr darauf zugreifen.
Wie kann ich das umgehen, also das nur dann leben aufgeräumt wird , wenn niemend es mehr benötigt?


----------



## bingo88 (27. April 2011)

Freddycbv schrieb:


> Ich war über Ostern weg, sonst hätt ich früher gefragt,
> Warum sollte man Zuweisungen im Konstruktor machen??
> Hat das nicht die selbe Wirkung wie IM Konstruktor??



Diese Initialisierungsliste kann konstante Werte setzen oder spezielle Konstruktoren von nicht-Zeiger-Objekten aufrufen.

```
class TestA
{
    public:
        TestA(int wert);
    ...
};

class TestB
{
public:
    TestB() : m_testA(42)
    {
        // ohne Initialisierungsliste geht hier nix, da kein parameterloser Konstruktor in TestA vorhanden ist!
         ...
    }

private:
    TestA m_testA;
};
```



Freddycbv schrieb:


> ```
> int main(void)
> {
> Soldat Offizier;
> ...


_Niemals Zeiger auf Objekte im Funktionsstack zurückgeben!_ Sobald du die Funktion verlässt wird das Objekt zerstört und der Zeiger ist ungültig (abgesehen davon überschreibst du hier nur den lokalen Zeiger innerhalb der Funktion, dein Objekt würde also sowieso nicht geändert). Wenn eine Funktion ein Objekt zurückgeben soll, musst du was anderes machen. In deinem Beispiel würde auch reichen, leben direkt zu setzen, da du ja bereits ein gültiges Objekt hast:

```
void NutzloseFunktion(Soldat *zeiger)
{
    if (zeiger) // falls zeiger NULL ist überspringen
        zeiger->SetLeben(39);
}
```


----------

