Fehler bei einer Klassenmethode



  • ... und ich sehe verflixt nicht warum.

    Hallo,

    ich arbeite mich gerade durch das Thema Klassen und habe mir dazu eine kleine Übung gemacht. Alles lief auch gut, bis ich die Klassenmethode 're_nutzung_01' eingeführt habe. Diese soll mir einfach nur einen string zurückgeben.

    Die Fehlermeldung:

    g++ -Wall -o flieger *.cpp *.h
    flieger.cpp:20: error: no ‘char* Flieger::re_nutzung_01()’ member function declared in class ‘Flieger’
    flieger.cpp: In member function ‘void Flieger::print_flieger()’:
    flieger.cpp:39: error: ‘re_nutzung_01’ was not declared in this scope
    Kompilierung fehlgeschlagen.
    

    Wenn ich das so richtig interpretiere, dann will mir g++ sagen, dass die benannte Funktion nicht deklariert ist, aber das ist sie meines Erachtens in der flieger.h doch 😞

    Hier der Code mit den entscheidenden Abschnnitten:

    //flieger.cpp
    #include "flieger.h"
    #include "debug.h"
    
    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    //// Konstruktoren ////
    
    // Standardkonstruktor
    Flieger::Flieger () {...}
    
    // Ellipse
    void Flieger::create (...) {...}  
    
    //// Methoden ////
    
    char* Flieger::re_nutzung_01(void)
    {
        switch(nutzung_01)      // Variablenzugriff in einer Klasse
        {
            case 0: return "zivil";
            case 1: return "militaerisch";
        }
    }
    
    // einmal alles ausgeben
    void Flieger::print_flieger (void)
    {
        cout << "Hersteller: " << hersteller << "\n";
        cout << "Typenbezeichnung: " << typenbezeichnung << "\n";
        cout << "Registratur: " << registratur << "\n";
        cout << "Tonnage: " << tonnage << "\n";
        cout << "Spannweite: " << spannweite << "\n";
        cout << "Geschwindigkeit: " << geschwindigkeit << "\n";
        cout << "Besatzung: " << besatzung << "\n";
        cout << "Nutzung: " << re_nutzung_01() << "\n";
    }
    

    und

    //flieger.h
    #ifndef _FLIEGER_H_
    #define _FLIEGER_H_
    
    #include "debug.h"
    
    #define _NA_ "NA"
    
    using namespace std;
    
    class Flieger
    {
    public:
        enum Nutzung_01 {ZIVIL, MILITAER};
        enum Nutzung_02 {FRACHT, PASSAGIER, PRIVAT, EINSATZ, FORSCHUNG}; 
    
    private:
        unsigned int besatzung;
        unsigned int tonnage;
        unsigned int geschwindigkeit;
        unsigned int spannweite;
        unsigned int nutzung_01;
        unsigned int nutzung_02;
        char registratur[7];
        char hersteller[20];
        char typenbezeichnung[20];
    
        //gibt die entspechenden char-Strings zurück
        char* re_nutzung_01(void);
    
    public:
        // Standardkonstruktor
        Flieger();
        // Parameterfehler
        void create (...);
        // einmal alles ausgeben
        void print_flieger (void);
    };
    
    #endif
    

    - habe das mit dem Buch verglichen und konnte nichts feststellen
    - mit der Methode als public ging es auch nicht

    Wer kann mir helfen???

    Vielen Dank schon mal im Vorraus
    Gruß
    Alex



  • Vermutlich hast du einen Tippfehler in deinem Code. Was du hier gepostet hast sieht OK aus, aber was du hier gepostet hast ist auch bearbeitet worden. Check nochmal deinen Original-Code.



  • Wie hustbaer schon sagt, ist der Fehler in dem Code nicht zu finden. Da du aber gerade C++ lernst, noch ein paar Anmerkungen:

    1. *.h hat in dem g++-Aufruf nichts zu suchen. Header werden per #include-Anweisung im Code benutzt

    2. Gerade als Anfänger solltest du statt

    char hersteller[20];
    

    lieber

    std::string hersteller;
    

    verwenden. Das wird dir noch viel Ärger ersparen und ist der C++-Weg für Strings

    1. aus dem gleichen Grund sollte deine Funktion "re_nutzung_01" auch einen std::string zurückgeben


    1. *.h hat in dem g++-Aufruf nichts zu suchen. Header werden per #include-Anweisung im Code benutzt

    Ja klar - ist ja eigentlich auch logisch 😃

    1. Gerade als Anfänger solltest du statt
    char hersteller[20];
    

    lieber

    std::string hersteller;
    

    verwenden. Das wird dir noch viel Ärger ersparen und ist der C++-Weg für Strings

    Das mit den Strings kannte ich noch nicht. War vorher nur auf C und da gab es sowas nicht 🙄

    Werde mir das aber noch angucken.

    Trotzdem kann das ja nicht der Fehler sein....

    hustbaer schrieb:

    Vermutlich hast du einen Tippfehler in deinem Code. Was du hier gepostet hast sieht OK aus, aber was du hier gepostet hast ist auch bearbeitet worden. Check nochmal deinen Original-Code.

    Hier noch mal der gesamte Code. Der ist ja recht übersichtlich (noch).

    main.cpp

    #include <iostream>
    
    #include "flieger.h"
    #include "debug.h"
    
    using namespace std;
    
    int main (void)
    {
       Flieger flieger_01;
    
       flieger_01.print_flieger();
    
       return 0;
    }
    

    flieger.h

    #ifndef _FLIEGER_H_
    #define _FLIEGER_H_
    
    #include "debug.h"
    #include <cstring>
    
    #define _NA_ "NA"
    
    using namespace std;
    
    class Flieger
    {
    public:
        enum Nutzung_01 {ZIVIL, MILITAER};
        enum Nutzung_02 {FRACHT, PASSAGIER, PRIVAT, EINSATZ, FORSCHUNG}; 
    
    private:
        unsigned int besatzung;
        unsigned int tonnage;
        unsigned int geschwindigkeit;
        unsigned int spannweite;
        unsigned int nutzung_01;
        unsigned int nutzung_02;
        char registratur[7];
        char hersteller[20];
        char typenbezeichnung[20];
    
        //gibt die entspechenden char-Strings zurück
        char* re_nutzung_01(void);
    
    public:
        // Standardkonstruktor
        Flieger();
        // Parameterfehler
        void create (...);
        // einmal alles ausgeben
        void print_flieger (void);
    };
    
    #endif
    

    flieger.cpp

    #include "flieger.h"
    #include "debug.h"
    
    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    //// Konstruktoren ////
    
    // Standardkonstruktor
    Flieger::Flieger ()
    {
        besatzung = 0;
        tonnage = 0;
        geschwindigkeit = 0;
        spannweite = 0;
        nutzung_01 = 0;
        nutzung_02 = 0;
        strncpy(registratur,"D-XXXX",sizeof(registratur)-1);
        registratur[sizeof(registratur)] = '\0';
        strncpy(hersteller,_NA_,sizeof(hersteller)-1);
        hersteller[sizeof(hersteller)] = '\0';
        strncpy(typenbezeichnung,_NA_,sizeof(typenbezeichnung)-1);
        typenbezeichnung[sizeof(typenbezeichnung)] = '\0';
    }
    
    // Ellipse (Parameterfehler)
    void Flieger::create (...)
    {
        cout << "Parameterfehler - es konnte kein Objekt 'Flieger' erstellt werden \n";
    }  
    
    //// Methoden ////
    
    char* Flieger::re_nutzung_01(void)
    {
        switch(nutzung_01)      // Variablenzugriff in einer Klasse
        {
            case 0: return "zivil";
            case 1: return "militaerisch";
        }
    }
    
    // einmal alles ausgeben
    void Flieger::print_flieger (void)
    {
        cout << "Hersteller: " << hersteller << "\n";
        cout << "Typenbezeichnung: " << typenbezeichnung << "\n";
        cout << "Registratur: " << registratur << "\n";
        cout << "Tonnage: " << tonnage << "\n";
        cout << "Spannweite: " << spannweite << "\n";
        cout << "Geschwindigkeit: " << geschwindigkeit << "\n";
        cout << "Besatzung: " << besatzung << "\n";
        cout << "Nutzung: " << re_nutzung_01() << "\n";     // hier muss noch das Objekt davor ?!?!?!?!
    }
    

    debug.h

    #ifndef _DEBUG_h_
    #define _DEBUG_H_
    
    #define DEBUG cout<<"Aktuell:_"<<__FUNCTION__<<"_"__LINE__<<"\n";
    
    #endif
    

    und noch mal der Fehler

    g++ -Wall -o flieger .cpp
    flieger.cpp:36: error: no ‘char
    Flieger::re_nutzung_01()’ member function declared in class ‘Flieger’
    flieger.cpp: In member function ‘void Flieger::print_flieger()’:
    flieger.cpp:55: error: ‘re_nutzung_01’ was not declared in this scope
    Kompilierung fehlgeschlagen.



  • Auf den ersten Blick ist das alles richtig. Kann es atm leider nicht in meiner IDE testen, schon versucht alle temporären dateien für das projekt mal zu löschen?

    Das einzige was ich mir momentan vorstellen könnte ist, das

    #define _NA_ "NA"
    

    zusammen mit

    #include "flieger.h"
    #include "debug.h"
    

    ein problem machen könnte - hab allerdings ka wofür das define überhaupt ist. In ner Stunde oder so schau ichs mir mal genauer an, wenn das Problem dann noch besteht.



  • Ach, die debug.h hast du ja auch angegeben.. na dann, vergiss meinen zweiten Absatz



  • kleiner Troll schrieb:

    Auf den ersten Blick ist das alles richtig. Kann es atm leider nicht in meiner IDE testen, schon versucht alle temporären dateien für das projekt mal zu löschen?

    Da hat sich tatsache was getan:

    Compiler schrieb:

    g++ -Wall -o flieger .cpp
    flieger.cpp: In member function ‘char
    Flieger::re_nutzung_01()’:
    flieger.cpp:41: warning: deprecated conversion from string constant to ‘char*’
    flieger.cpp:42: warning: deprecated conversion from string constant to ‘char*’
    flieger.cpp:44: warning: control reaches end of non-void function
    Kompilierung erfolgreich beendet.

    Aber das Ergebnis ist mir immernoch unlogisch.

    kleiner Troll schrieb:

    Das einzige was ich mir momentan vorstellen könnte ist, das

    #define _NA_ "NA"
    

    Der Spaß ist auch nur zur Übung... Er soll es ermöglichen schnell "NA" durch z.B. "unbekannt" zu ersetzen. Ist aber nicht wichtig.



  • Das Ergebnis ist wiederum nicht unlogisch. "zivil" und "militaerisch" sind vom typ const char*, du gibst aber nur char* zurück. Ist mir nicht aufgefallen, aber überrascht mich ein bißchen, dass es sogar geht. Zugegebenermaßen ist das wegen C kompabilität durchaus logisch.

    Normalerweise wenn du versuchst einen const typ in einen nicht-const typ umzuwandeln gibts einen compilerfehler.



  • Noch ein nachtrag: "control reaches end of non-void function " ist ein problem, weil du für den Fall das der switch kein "0" oder "1" findet einfach durchfällt, und was macht er dann? Er hat ja keine Anweisung, was er returnen soll.

    Du kannst dir btw das (void) bei funktionen für die parameter hinten in c++ sparen, und verwende wenns geht keine defines die mit einem unterstrich beginnen, defines dieser art und weise werden von der Implementierung der stl verwendet und sind also reserviert.



  • #ifndef _DEBUG_h_ // <-- das sind nicht die gleichen Makronamen!
    #define _DEBUG_H_
    

    Außerdem darfst du dem Standard nach diese Bezeichner eh nicht verwenden - alles, was mit [A-Z] anfängt, ist für die Implementation reserviert, ebenso wie alles, was __ (zwei Unterstriche) irgendwo im Namen hat. Zusätzlich ist im globalen Namensraum alles reserviert, was mit einem Unterstrich beginnt. Ob sich speziell diese Makros mit deiner Implementation beißen, kann ich aus der Entfernung nicht sagen, ich halte es aber für möglich - gerade bei _DEBUG_H und _NA_.



  • hey super - es funktioniert. Dann kann es endlich auch weiter gehen

    kleiner Troll schrieb:

    Das Ergebnis ist wiederum nicht unlogisch. "zivil" und "militaerisch" sind vom typ const char*, du gibst aber nur char* zurück. Ist mir nicht aufgefallen, aber überrascht mich ein bißchen, dass es sogar geht. Zugegebenermaßen ist das wegen C kompabilität durchaus logisch.

    Normalerweise wenn du versuchst einen const typ in einen nicht-const typ umzuwandeln gibts einen compilerfehler.

    Wusste nicht, dass C++ da so penibel ist. In C ist bei mir das const so gut wie nie zu finden... 😮

    kleiner Troll schrieb:

    Noch ein nachtrag: "control reaches end of non-void function " ist ein problem, weil du für den Fall das der switch kein "0" oder "1" findet einfach durchfällt, und was macht er dann? Er hat ja keine Anweisun 😉 g, was er returnen soll.

    das lässt sich beheben 🕶

    kleiner Troll schrieb:

    Du kannst dir btw das (void) bei funktionen für die parameter hinten in c++ sparen, und verwende wenns geht keine defines die mit einem unterstrich beginnen, defines dieser art und weise werden von der Implementierung der stl verwendet und sind also reserviert.

    &@seldon
    Ok, macht Sinn. Nur doof, dass die Beispiele im Buch so sind. Aber ich werde es beherzigen. Kann ja sein, dass man trotzdem mal nen Treffer hat. 😃

    Damit danke - war sehr lehr-&hilfreich 👍

    Gruß
    Alex

    PS: der korrigierte Code:

    main.cpp

    #include <iostream>
    
    #include "flieger.h"
    #include "debug.h"
    
    using namespace std;
    
    int main (void)
    {
       Flieger flieger_01;
    
       flieger_01.print_flieger();
    
       return 0;
    }
    

    flieger.h

    #ifndef FLIEGER_H
    #define FLIEGER_H
    
    #include "debug.h"
    #include <cstring>
    
    #define MNA "NA"
    
    using namespace std;
    
    class Flieger
    {
    public:
        enum Nutzung_01 {ZIVIL, MILITAER};
        enum Nutzung_02 {FRACHT, PASSAGIER, PRIVAT, EINSATZ, FORSCHUNG}; 
    
    private:
        unsigned int besatzung;
        unsigned int tonnage;
        unsigned int geschwindigkeit;
        unsigned int spannweite;
        unsigned int nutzung_01;
        unsigned int nutzung_02;
        char registratur[7];
        char hersteller[20];
        char typenbezeichnung[20];
    
        //gibt die entspechenden char-Strings zurück
        const char* re_nutzung_01(void);
    
    public:
        // Standardkonstruktor
        Flieger();
        // Parameterfehler
        void create (...);
        // einmal alles ausgeben
        void print_flieger (void);
    };
    
    #endif
    

    flieger.cpp

    #include "flieger.h"
    #include "debug.h"
    
    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    //// Konstruktoren ////
    
    // Standardkonstruktor
    Flieger::Flieger ()
    {
        besatzung = 0;
        tonnage = 0;
        geschwindigkeit = 0;
        spannweite = 0;
        nutzung_01 = 0;
        nutzung_02 = 0;
        strncpy(registratur,"D-XXXX",sizeof(registratur)-1);
        registratur[sizeof(registratur)] = '\0';
        strncpy(hersteller,MNA,sizeof(hersteller)-1);
        hersteller[sizeof(hersteller)] = '\0';
        strncpy(typenbezeichnung,MNA,sizeof(typenbezeichnung)-1);
        typenbezeichnung[sizeof(typenbezeichnung)] = '\0';
    }
    
    // Ellipse (Parameterfehler)
    void Flieger::create (...)
    {
        cout << "Parameterfehler - es konnte kein Objekt 'Flieger' erstellt werden \n";
    }  
    
    //// Methoden ////
    
    const char* Flieger::re_nutzung_01(void)
    {
        switch(nutzung_01)      // Variablenzugriff in einer Klasse
        {
            case 0: return "zivil";
            case 1: return "militaerisch";
        }
        return "huhu";  // damit der Compiler glücklich ist
    }
    
    // einmal alles ausgeben
    void Flieger::print_flieger (void)
    {
        cout << "Hersteller: " << hersteller << "\n";
        cout << "Typenbezeichnung: " << typenbezeichnung << "\n";
        cout << "Registratur: " << registratur << "\n";
        cout << "Tonnage: " << tonnage << "\n";
        cout << "Spannweite: " << spannweite << "\n";
        cout << "Geschwindigkeit: " << geschwindigkeit << "\n";
        cout << "Besatzung: " << besatzung << "\n";
        cout << "Nutzung: " << re_nutzung_01() << "\n";
    }
    

    debug.h

    #ifndef DEBUG_H
    #define DEBUG_H
    
    #define DEBUG cout<<"Aktuell:_"<<__FUNCTION__<<"_"__LINE__<<"\n";
    
    #endif
    


  • __PRETTY_FUNCTION__ (linux,gcc) unter Kleinweich gibts was ähnliches .. kannste googlen

    Gratulation zu deinem Statischen Flieger den du jetzt wie oft gepostet hast? 3 Mal? achja .. das "huhu" könntest du auch durch ein default: return "gibbsNich"; direct im Switch erschlagen und print_flieger durch eine passende Überladung für operator<<() deines Objektes 😉 aber das kommt vermutlich in weiteren Kapiteln. Ich hoffe nur da kommen noch getter/setter damit du deinen Flieger ausbauen kannst, trotz netter enums gibts ja zZ nur die eine Variante.



  • Ich würde dir empfehlen dich über std::string zu erkundigen. Das erspart dir einige Arbeit mit char-pointern, char-arrays und erleichtert das Programmieren.



  • Wusste nicht, dass C++ da so penibel ist. In C ist bei mir das const so gut wie nie zu finden... 😮

    Ich hoffe mal, das is da nie zufinden :>

    const gibt's meines wissens in C doch überhaupt nicht. Oder irre ich mich da? Hab nie wirklich mit C gearbeitet. (Man kann übrigens ein const schon mit const_cast wegmachen, aber das sollte man sich wirklich gut überlegen.. ich habs noch nie gebraucht)



  • const gibt es in C schon, es wird aber im Zusammenhang mit Zeigern ziemlich lax gehandhabt.

    Was const_cast angeht, man braucht es in C++ wirklich sehr selten (bzw. wenn man es häufig braucht, macht man etwas gründlich falsch). Scott Meyers schlägt zur Vermeidung doppelter Codehaltung vor, const_cast für überladene Methoden zu benutzen, die sich nur durch den const-Qualifier auf *this unterscheiden. Code entnommen aus Effective C++, Item 3:

    class TextBlock {
    public:
      const char &operator[](std::size_t position) const {
        ...
        ...
        ...
        return text[position];
      }
    
      char &operator[](std::size_t position)  {
        return const_cast<char&>(static_cast<TextBlock const &>(*this)[position]);
      }
    
      ...
    };
    

    ...und dann gibt es da noch den Umgang mit alten C-Bibliotheken, denen const-Qualifier fehlen, aber damit hat es sich eigentlich auch schon.


Anmelden zum Antworten