Unterschiedliche C++ Compiler



  • Hallo alle miteinander,

    ich benutze überwiegend die MinGWStudio Entwicklungsumgebung und arbeite mich gerade durch das Buch "C++ in 21 Tagen" (Jesse Liberty). Nun ist ein Quellcode aufgetaucht (direkt nach Kapitel 14 beim Rückblick auf Woche 2), der lediglich mit Visual C++ 6 von Microsoft funktioniert.

    Der Fehlerproduzent ist folgende Zeile:

    void (Part::*pFunc)()const = Part::Display;
    

    Die Fehlermeldung:

    "invalid use of non-static member function `virtual void Part::Display() const'"

    Warum klappt das nicht mit dem Compiler von der MinGWStudio Umgebung? Wie müsste ich es umschreiben, damit es funktioniert?

    - - - - - - - - - - - - - - -

    Für diejenigen, die das Buch nicht besitzen, hier der gesamte Quellcode:

    #include <iostream.h>
    
     // **************** Teile ************
    
     // Abstrakte Basisklasse für die Teile
     class Part
     {
     public:
        Part():itsPartNumber(1) {}
        Part(int PartNumber):itsPartNumber(PartNumber){}
        virtual ~Part(){};
        int GetPartNumber() const { return itsPartNumber; }
        virtual void Display() const =0;  // muss überschrieben werden
     private:
        int itsPartNumber;
     };
    
     // Implementierung einer abstrakten Funktion, damit
     // abgeleitete Klassen die Funktion überschreiben
     void Part::Display() const
     {
         cout << "\nTeilenummer: " << itsPartNumber << endl;
     }
    
     // **************** Autoteile ************
    
     class CarPart : public Part
     {
     public:
        CarPart():itsModelYear(94){}
        CarPart(int year, int partNumber);
        virtual void Display() const
       {
          Part::Display(); cout << "Baujahr: ";
          cout << itsModelYear << endl;
       }
     private:
        int itsModelYear;
     };
    
     CarPart::CarPart(int year, int partNumber):
        itsModelYear(year),
        Part(partNumber)
     {}
    
     // **************** Flugzeugteile ************
    
     class AirPlanePart : public Part
     {
     public:
        AirPlanePart():itsEngineNumber(1){};
        AirPlanePart(int EngineNumber, int PartNumber);
        virtual void Display() const
       {
          Part::Display(); cout << "Motor-Nr.: ";
          cout << itsEngineNumber << endl;
       }
     private:
        int itsEngineNumber;
     };
    
     AirPlanePart::AirPlanePart(int EngineNumber, int PartNumber):
        itsEngineNumber(EngineNumber),
        Part(PartNumber)
     {}
    
     // **************** Teile-Knoten ************
     class PartNode
     {
     public:
        PartNode (Part*);
        ~PartNode();
        void SetNext(PartNode * node) { itsNext = node; }
        PartNode * GetNext() const;
        Part * GetPart() const;
     private:
        Part *itsPart;
        PartNode * itsNext;
      };
    
      // Implementierungen von PartNode ...
    
      PartNode::PartNode(Part* pPart):
      itsPart(pPart),
      itsNext(0)
      {}
    
      PartNode::~PartNode()
      {
         delete itsPart;
         itsPart = 0;
         delete itsNext;
         itsNext = 0;
      }
    
      // Liefert NULL zurück, wenn kein nächster PartNode vorhanden
      PartNode * PartNode::GetNext() const
      {
            return itsNext;
      }
    
      Part * PartNode::GetPart() const
      {
         if (itsPart)
            return itsPart;
         else
            return NULL; // Fehler
      }
    
      // **************** Teileliste ************
      class PartsList
      {
      public:
         PartsList();
         ~PartsList();
         // benötigt Kopierkonstruktor und Zuweisungsoperator! 
         Part*      Find(int & position, int PartNumber)  const;
         int      GetCount() const { return itsCount; }
         Part*      GetFirst() const;
         static     PartsList& GetGlobalPartsList()
       {
          return  GlobalPartsList;
       }
         void       Insert(Part *);
         void       Iterate(void (Part::*f)()const) const;
         Part*      operator[](int) const;
      private:
         PartNode * pHead;
         int itsCount;
         static PartsList GlobalPartsList;
      };
    
      PartsList PartsList::GlobalPartsList;
    
      // Implementierungen für Liste...
    
      PartsList::PartsList():
         pHead(0),
         itsCount(0)
         {}
    
      PartsList::~PartsList()
      {
         delete pHead;
      }
    
      Part*   PartsList::GetFirst() const
      {
         if (pHead)
            return pHead->GetPart();
         else
            return NULL;  // Fehler auffangen
      }
    
      Part *  PartsList::operator[](int offSet) const
      {
         PartNode* pNode = pHead;
    
         if (!pHead)
            return NULL; // Fehler auffangen
    
         if (offSet > itsCount)
            return NULL; // error
    
         for (int i=0;i<offSet; i++)
            pNode = pNode->GetNext();
    
        return   pNode->GetPart();
      }
    
      Part*   PartsList::Find(int & position, int PartNumber)  const
      {
         PartNode * pNode = 0;
         for (pNode = pHead, position = 0;
               pNode!=NULL;
               pNode = pNode->GetNext(), position++)
         {
            if (pNode->GetPart()->GetPartNumber() == PartNumber)
               break;
         }
         if (pNode == NULL)
            return NULL;
         else
            return pNode->GetPart();
      }
    
      void PartsList::Iterate(void (Part::*func)()const) const
      {
         if (!pHead)
            return;
         PartNode* pNode = pHead;
         do
            (pNode->GetPart()->*func)();
         while (pNode = pNode->GetNext());
      }
    
      void PartsList::Insert(Part* pPart)
      {
         PartNode * pNode = new PartNode(pPart);
         PartNode * pCurrent = pHead;
         PartNode * pNext = 0;
    
         int New =  pPart->GetPartNumber();
         int Next = 0;
         itsCount++;
    
         if (!pHead)
         {
            pHead = pNode;
            return;
         }
    
         // ist dieser kleiner als head
         // dann ist dies der neue head
         if (pHead->GetPart()->GetPartNumber() > New)
         {
            pNode->SetNext(pHead);
            pHead = pNode;
            return;
         }
    
         for (;;)
         {
            // gibt es keinen nächsten Knoten, den neuen anhängen
            if (!pCurrent->GetNext())
            {
               pCurrent->SetNext(pNode);
               return;
            }
    
            // gehört der Knoten zwischen diesen und den nächsten,
            // dann hier einfügen, ansonsten zu nächstem Knoten
            pNext = pCurrent->GetNext();
            Next = pNext->GetPart()->GetPartNumber();
            if (Next > New)
            {
               pCurrent->SetNext(pNode);
               pNode->SetNext(pNext);
               return;
            }
            pCurrent = pNext;
         }
      }
    
      int main()
      {
         PartsList&pl = PartsList::GetGlobalPartsList();
         Part * pPart = 0;
         int PartNumber;
         int value;
         int choice;
    
         while (1)
         {
            cout << "(0)Beenden (1)Auto (2)Flugzeug: ";
            cin >> choice;
    
            if (!choice)
               break;
    
            cout << "Neue Teilenummer?: ";
            cin >>  PartNumber;
    
            if (choice == 1)
            {
               cout << "Baujahr?: ";
               cin >> value;
               pPart = new CarPart(value,PartNumber);
            }
            else
            {
               cout << "Motor-Nummer?: ";
               cin >> value;
               pPart = new AirPlanePart(value,PartNumber);
            }
    
            pl.Insert(pPart);
         }
         void (Part::*pFunc)()const = Part::Display;
         pl.Iterate(pFunc);
        return 0;
      }
    


  • Ich geb dir nur einen tipp: kauf dir ein ordentliches Buch, nicht den ich lerne X in Y Tagen schrott.



  • Schreibt man da nicht normalerweise ein & vor den Funktionsnamen?

    EDIT: @otze: Grundsätzlich stimme ich dir zu, aber nun hat er es schon mal, und zum Reinschnuppern ist es gut genug. Wenn es ihn nach dem Schmökern in diesem Buch immer noch interessiert, dann kann er ja mal mit was Richtigem anfangen.



  • otze schrieb:

    Ich geb dir nur einen tipp: kauf dir ein ordentliches Buch, nicht den ich lerne X in Y Tagen schrott.

    Ich fand es bisher recht ausführlich und es hat mich schon sehr weit gebracht. Bis auf diese eine Stelle!

    Zudem weiß ich nicht, was du mit "ordentlichem" Buch meinst! ISBN?

    Ringding schrieb:

    Schreibt man da nicht normalerweise ein & vor den Funktionsnamen?

    pFunc ist ein Elementfunktionszeiger!



  • sirvenue schrieb:

    otze schrieb:

    Ich geb dir nur einen tipp: kauf dir ein ordentliches Buch, nicht den ich lerne X in Y Tagen schrott.

    Ich fand es bisher recht ausführlich und es hat mich schon sehr weit gebracht. Bis auf diese eine Stelle!

    naja, vll solltest du dich mal bzgl modularisierung schlau machen.
    Deine klassen könntest du alle in einzelne header und source dateien packen und auch die main in eine seperate datei. oder hast du die nur fürs forum zusammenkopiert? wenn ja ok.
    Dazu kommt noch das du
    [ cpp ] tags statt [ code ] benutzen solltest und das du

    statt

    #include<iostream.h>
    

    einfach

    #include<iostream>
    

    schreiben solltest.

    Den code hab ich mir aber ncoh nicht genauer angeguggt



  • shapeless schrieb:

    naja, vll solltest du dich mal bzgl modularisierung schlau machen.
    Deine klassen könntest du alle in einzelne header und source dateien packen und auch die main in eine seperate datei. oder hast du die nur fürs forum zusammenkopiert? wenn ja ok.
    Dazu kommt noch das du
    [ cpp ] tags statt [ code ] benutzen solltest und das du

    statt

    #include<iostream.h>
    

    einfach

    #include<iostream>
    

    schreiben solltest.

    Den code hab ich mir aber ncoh nicht genauer angeguggt

    Ich habe es der übersicht wegen zusammengeschrieben. Die Einbindung von "iostream" hatte keine Probleme gemacht und ich selbst schreibe es auch immer <iostream>, im Buch-Quellcode war es jedoch mit ".h".



  • sirvenue schrieb:

    shapeless schrieb:

    naja, vll solltest du dich mal bzgl modularisierung schlau machen.
    Deine klassen könntest du alle in einzelne header und source dateien packen und auch die main in eine seperate datei. oder hast du die nur fürs forum zusammenkopiert? wenn ja ok.
    Dazu kommt noch das du
    [ cpp ] tags statt [ code ] benutzen solltest und das du

    statt

    #include<iostream.h>
    

    einfach

    #include<iostream>
    

    schreiben solltest.

    Den code hab ich mir aber ncoh nicht genauer angeguggt

    Ich habe es der übersicht wegen zusammengeschrieben. Die Einbindung von "iostream" hatte keine Probleme gemacht und ich selbst schreibe es auch immer <iostream>, im Buch-Quellcode war es jedoch mit ".h".

    gut dann sind diese Sachen ja geklärt 😉

    aber mal zum code. ich bin nicht soo fit was funktionszeiger angeht aber
    die zeile die du ansprichst ist mir nicht geheuer. Du hast eine rein virtuelle methode, willst auf sie einen zeiger zeigen lassen, aber das geht nicht ohen instanz, welche man nicht erzeugen kann, weil es ja eine abstrakte klasse ist.
    also kannst du sie nur static oder virual machen ...hmm wie gesagt ich bin da kein experte aber da ist was faul.



  • Ok, habe soweit verstanden, was du meinst. Das Merkwürdige ist nur, in Visual C++ 6 funktioniert es ohne Probleme...

    Mal so nebenher - brauche ich das denn wirklich alles für die Programmierung auf z.B. Windows-Systemen?



  • hmm auch wenns komisch klingen mag aber hast du mal
    das hier

    void (Part::*pFunc)()const = &Part::Display;
    

    probiert ?
    mit gcc gehts auf diese weise.

    Naja, dennoch werde ich mich wohl diesbezüglich mal weiterinformieren müssen...
    wollte keine unnötige verwirrung stiften



  • sirvenue schrieb:

    Mal so nebenher - brauche ich das denn wirklich alles für die Programmierung auf z.B. Windows-Systemen?

    Naja, ich weiss nicht was du später machen willst, aber ich denke Vererbung und Funktionspointer und solche Sachen, sind Dinge die man als Werkzeug braucht,
    deshalb würde ich sagen japp das meiste brauchst du wieder.



  • Vielen Dank, bei mir funktioniert es ebenfalls! Man muss also die Adresse mit übergeben. Visual Studio erkennt es scheinbar auch ohne das "&".

    Für dich als kleine Auffrischung (wenn es wirklich so wichtig ist 😉 ):

    Man könnte es auch so schreiben:

    // konstanten Elementfunktionszeiger einrichten, der "void" zurückliefert und keine Werte (daher die leeren Klammern "()") übernimmt und diesen NULL setzen
    
         void (Part::*pFunc)()const = NULL;
    
    // Adresse von der Elementfkt. im Nachhinein übergeben
         pFunc = &Part::Display;
    


  • sirvenue schrieb:

    Visual Studio erkennt es scheinbar auch ohne das "&".

    Ein Fehler beim MSC 6. Wurde hier aber schon tausendmal diskutiert, dass der nicht standardkonform ist.



  • sirvenue schrieb:

    pFunc ist ein Elementfunktionszeiger!

    Gut, dass du mittlerweile auch schon draufgekommen bist, dass es mit & funktioniert... 🙄


Anmelden zum Antworten