Ergebnis 1 bis 5 von 5

Thema: [C++]Zeiger in Klassen

  1. #1

    [C++]Zeiger in Klassen

    Also, ich habe dieses mal zwei Fragen bezüglich Zeiger innerhalb von Klassen. Als Beispiel habe ich folgenden Beispielcode geschrieben:
    Code:
    #include <iostream>
    class Cat
    {
          public:
                 Cat();
                 ~Cat();
                 void setAge(int age) { *itsAge = age; }
                 int getAge() { return *itsAge; }
          private:
                  int * itsAge;
    };
    Cat::Cat()
    {
              itsAge = new int(5);
    }
    Cat::~Cat()
    {
               delete itsAge;
    }
    int main()
    {
        Cat * Momo = new Cat;
        std::cout << "Momo ist ein Katere.\n";
        std::cout << "Er war " << Momo->getAge() << " Jahre alt, als Peter ihn bekommen hat.\n";
        Momo->setAge(9);
        std::cout << "Doch jetzt ist er mittlerweile schon " << Momo->getAge() << " Jahre alt.\n";
        std::cin.get();
        delete Momo;
        return 0;
    }
    Der Code an sich funktioniert ja einwandfrei, aber die Definition der beiden Elementfunktionen getAge und setAge haben bei mir, als ich den Code zum ersten mal geschrieben habe, zu denken gegeben. Denn wenn ich diese ausserhalb von class Cat { ... }; definiere, gibt der Compiler folgende Fehlermeldung aus:
    Zitat Zitat
    ISO C++ forbids declaration of `setAge' with no type
    Wieso geht das nicht? Wieso erlaubt der Compiler die Definition von setAge und getAge ausserhalb der eigentlichen Klassendeklaration nicht? Denn den Konstruktor und den Destruktor definiere ich ja auch ausserhalb von class Cat { ... }; ohne das der Compiler Einwände dagegen hat.

    Meine zweite Frage betrifft den Zeiger im Konstuktor (Zeile 14). Warum darf ich vor dem itsAge = new int(5) kein * setzten, während ich es bei der Elementfunktionsdefinition ( - wie ich diese Fachchinesisch liebe - ) von setAge verwenden muss ohne dass ich eine Fehlermeldung vom Compiler erhalte.

    Mfg Biosfear

  2. #2
    Zur 2ten Frage:
    Manche schreiben pointer so:
    typ *pointer;
    ich schreibe sie so:
    typ* pointer;

    Dann ist für mich klar, dass es vom Typ "typ" ist, und durch den direkten Stern auch ein Pointer. Warum sollte der Stern an dem Namen sein? Der Name ist ja bei Pointer oder Variable gleich, nur der Typ muss gekenntzeichnet werden. Nun zu der Frage. Wenn du einen Pointer erstmalig erstellst, dann muss das mit * sein. Also typ* pointer. Dann hast du einen Pointer der noch auf keinen Bereich zeigt. (Afaik haben frisch deklarierte (undefinierte) Variablen aber immer einen undefinierten Inhalt der alles mögliche sein kann, aber meist nicht 0. Daher ist so ein pointer gefährlich, da er scheinbar eine Adresse beinhaltet, diese aber willkürlich irgendein Zahlenwert ist.) Jedenfalls musst du diesem pointer nun noch einen Wert zuweisen. Das geschieht mit dem Zuweisungsoperator " = ".

    Also pointer = &a;
    Damit wird die Adresse der Variable a in den pointer geschrieben bzw der Pointer zeigt nun darauf. Das gleiche gilt bei dynamischem Speicher mittels new-Operator:
    pointer = new int;
    Der Stern (*) hingegen ist nach der Deklaration auch ein Symbol für den Inhalt des Pointers. Während du also mit pointer = &a; die Adresse des pointers auf a richtest, wird mit *pointer = &a; der Inahalt des Pointers, das, worauf er zeigt, geändert. In diesem Fall ist der neue Wert an der Stelle des Pointers dann die Adresse von a, was natürlich meist keinen Sinn ergibt. Sinnvoller wäre da *pointer = a; damit weißt du dem Inhalt des gepointeten Bereichs den Wert der Variable a zu.
    Im Übrigen machst du das bei getAge() ja schon richtig, du gibst per return den gepointeten Wert zurück und nicht den Pointer selbst, da du ein Stern (*) vorransetzt, der kennzeichnet, dass es um den Inhalt und nicht den Pointer selbst geht.
    Das ist also der Unterschied zwischen * und ohne Stern NACH der Deklaration des Pointers.


    EDIT: Problem 1:
    So kannst du die Methoden auch außerhalb definieren:

    Code:
    #include <iostream>
    
    using namespace std;
    
    class Cat
    {
          public:
                 Cat();
                 ~Cat();
                 void setAge(int age);
                 int getAge( void );
          private:
                  int * itsAge;
    };
    Cat::Cat()
    {
              itsAge = new int(5);
    }
    Cat::~Cat()
    {
               delete itsAge;
    }
    
    void Cat::setAge(int age)
    {
            *itsAge = age;
    }
    
    int Cat::getAge( void )
    {
            return *itsAge;
    }
    
    int main()
    {
        Cat * Momo = new Cat;
        std::cout << "Momo ist ein Katere.\n";
        std::cout << "Er war " << Momo->getAge() << " Jahre alt, als Peter ihn bekommen hat.\n";
        Momo->setAge(9);
        std::cout << "Doch jetzt ist er mittlerweile schon " << Momo->getAge() << " Jahre alt.\n";
        std::cin.get();
        delete Momo;
        return 0;
    }

    Geändert von Ynnus (08.08.2005 um 16:26 Uhr)

  3. #3
    Danke für deine ausführliche Antwort und den Code zu Definition der Elementfunktionen ausserhalb der Klassendeklaration Ynnus. Ebenfalls vielen danke für deine Erklärung der ganzen Pointergeschichte, die um einiges einfacher zu verstehen ist, als die im Buch, mit dem ich arbeite. Aber:

    Zitat Zitat von Ynnus
    Zur 2ten Frage:
    Während du also mit pointer = &a; die Adresse des pointers auf a richtest, wird mit *pointer = (&)a; der Inahalt des Pointers, das, worauf er zeigt, geändert.
    Genau das ist der springende Punkt, der mich bei dem Codebeispiel stutzig macht.
    Wenn ich folgenden Code schreibe, beabsichte ich ja demzufolge, itsAge den Wert von age zu übergeben.
    Code:
    void Cat::setAge(int age)
    {
            *itsAge = age;
    }
    Beim Konstruktor will ich ja genau das selbe: Ich will dem Pointer itsAge den Wert (die Integerzahl 5) zuweisen.
    Code:
    Cat::Cat()
    {
              itsAge = new int(5);
    }
    Aber wieso wird bei hierbei auf * verzichtet, obwohl ja eigentlich der Wert/Inhalt angesprochen werden soll?

    Mfg Biosfear

    Geändert von Biosfear (08.08.2005 um 19:13 Uhr)

  4. #4
    Code:
    void Cat::setAge(int age)
    {
            *itsAge = age;
    }
    Da age ein int ist und es in diesem Fall unsinnig ist den Pointer itsAge auf ein int zu setzten, müssen wir itsAge vorher dereferenzieren, d.h. zu einem int machen. Dann stimmt das ganze wieder. int = int.
    Code:
    Cat::Cat()
    {
              itsAge = new int(5);
    }
    new int(5) liefer aber kein int zurück sondern einen Pointer auf ein int. Daher müssen wir itsAge nicht dereferenzieren, weil wir ja den Pointer selbst setzen wollen. Es wäre übrigens unsinnig in dem Stadium itsAge zu dereferenzieren, weil der Pointer noch uninitialisiert ist. Das heißt er zeigt auf einen zufälligen Ort irgendwie im speicher. Davon lesen oder gar schreiben kann zu erheblichen Fehlern führen.

  5. #5
    Zitat Zitat von Dingsi
    Da age ein int ist und es in diesem Fall unsinnig ist den Pointer itsAge auf ein int zu setzten, müssen wir itsAge vorher dereferenzieren, d.h. zu einem int machen. Dann stimmt das ganze wieder. int = int.[CODE]
    Cat:at()

    new int(5) liefer aber kein int zurück sondern einen Pointer auf ein int. Daher müssen wir itsAge nicht dereferenzieren, weil wir ja den Pointer selbst setzen wollen.
    Ah, genau, klingt und ist einleuchtend ! Und auf einmal erscheint mir das ganze nun endlich plausibel und ich hab` die ganze Pointergeschichte einigermassen begriffen! Mann, das hat aber auch lange gedauert, bis ich das endlich begriffen habe. Ich sitze nämlich schon ne ganze Weile vor dem Code und frage mich "wieso?!". Zwar wird im Buch vieles (sehr vieles) beschrieben, aber die Frage wurde mir erst jetzt beantwortet. Der Einsatz, Zweck und die Handhabung von Pointern (in dieser Grössenordnung) sind mir nun aber schlussendlich eigentlich soweit klar. Danke an euch beide.

    Mfg Biosfear

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •