Problem mit Vererbung abstrakter Methode



  • Hallo zusammen,

    ich versuche gerade das Entwurfsmuster "Strategie" in C++ zu implementieren. Ich tat dies bereits mehrere Mal in Java und stehe gerade vor einem doofen Problem. Hier ist mein Code:

    class scheduler {
    
    	protected:
    		virtual void scheduleAlgorithm() = 0; //eine abstrakte Methode, die erst in eine Kindklasse implementiert werden soll
    		//...
    
    	public:
    		/...		
    
    };
    //...
    class fifo : public scheduler{
    
    	public: 	
    		fifo(std::vector<process>);
    };
    
    //...
    void fifo::scheduleAlgorithm() { //unbekannt -> Fehler
    
    }
    

    Warum kann ich nun die Methode "scheduleAlgorithm" nicht implementieren?
    ‘void fifo::scheduleAlgorithm()’ member function declared in class ‘fifo’

    fifo erbt doch von scheduler. Was mache ich in C++ falsch?

    Vielen Dank
    LG, freakC++



  • class scheduler {
    
    	protected:
    		virtual void scheduleAlgorithm() = 0; //eine abstrakte Methode, die erst in eine Kindklasse implementiert werden soll
    		//...
    
    	public:
    		/...		
    
    };
    //...
    class fifo : public scheduler{
    
    	public: 	
    		fifo(std::vector<process>);
                    void scheduleAlgorithm();//musst sie schon deklarieren
    };
    
    //...
    void fifo::scheduleAlgorithm() { //unbekannt -> Fehler
    
    }
    


  • class fifo : public scheduler
    {
        public:    
            fifo(std::vector<process>);
            virtual void scheduleAlgorithm();
    };
    

    Eine virtuelle Funktion musst du überschreiben.



  • Ah ok 🙂 Das wusste ich nicht. Gibt es dafür einen Grund? Immerhin erbe ich die Methode, sodass sie deklariert sein sollte. In Java ist das nicht nötig.

    Bis jetzt funktioniert alles soweit, doch mich quält ein Segmentation Error. Könnt ihr mal drüber schauen?

    class scheduler {
    
    	protected:
    		virtual void scheduleAlgorithm() = 0; //eine virtuelle Methode für die Kinder
    		std::vector<process> processes;	
    
    	public:
    		scheduler(std::vector<process> p) {processes = p;}
    		~scheduler(){};
    		std::vector<std::string> schedule(int);
    
    };
    
    std::vector<std::string> scheduler::schedule(int duration) {
    
    	std::cout << "MamaScheduler" << std::endl;
    	scheduleAlgorithm(); //Aufruf der virtuellen Methode
    }
    
    class fifo : public scheduler{ //ein Kind von scheduler
    
    	public: 	
    		fifo(std::vector<process>);
    		~fifo(){}
    		void scheduleAlgorithm(); 
    };
    
    fifo::fifo(std::vector<process> p) : scheduler(p) {
    
    }
    
    void fifo::scheduleAlgorithm() {
    	std::cout << "Fifo-Algorithmus" << std::endl; //die virtuelle Methode wird definiert
    }
    

    In der main mache ich dann folgendes:

    scheduler* test = new fifo(proc); //edit: Rechtschreibfehler verbessert
    vector<string> res = test->schedule(totalDuration); //Diese Methode verursacht den Fehler
    delete test;
    

    Die Ausgabe erfolg nach meinen Erwartungen, doch danach kommt es zu einem Speicherzugriffsfehler:

    MamaScheduler
    Fifo-Algorithmus
    ./run.s: line 3: 5885 Segmentation fault ./scheduler "processes.txt"

    Ich arbeite mit keinen Zeigern (außer für "test"). Ich dachte, dass es irgendwie am Aufräumen liegt, doch den (sinnlosen) Destuktor rufe ich auf.

    Weiß jemand weiter?

    Vielen Dank
    LG, freakC++



  • Du musst keinen Destruktor aufrufen, das wird automatisch gemacht!
    Da du beim Erstellen von test das Gleichheitszeichen vergessen hast, nehme ich an, dass du den Code nur "grob" wiedergegeben hast.
    Copy&Paste bitte alles!



  • sorry, alles ist copy und paste. Nur die main habe ich abgeschrieben^^



  • freakC++ schrieb:

    sorry, alles ist copy und paste. Nur die main habe ich abgeschrieben^^

    Eventuell solltest Du die Warnstufe Deines Compilers etwas höher drehen.
    Funktionen, die einen Wert zurückgeben sollen und es dann doch nicht tun sind schlecht.

    Was soll der Quatsch? ist das wirklich notwendig wegen so einem Mist (dem Segfault) zu posten, anstatt sich den Code anzuschauen?
    Dafür sollte Dir jeder Professor die Hammelbeine langziehen!



  • doh! schrieb:

    Eventuell solltest Du die Warnstufe Deines Compilers etwas höher drehen.

    Nicht nötig gewesen.

    doh! schrieb:

    Funktionen, die einen Wert zurückgeben sollen und es dann doch nicht tun sind schlecht.

    In der Tat! Das war der Fehler!

    doh! schrieb:

    Was soll der Quatsch?

    Welcher Quatsch?

    doh! schrieb:

    ist das wirklich notwendig wegen so einem Mist (dem Segfault) zu posten, anstatt sich den Code anzuschauen?

    Da ein SegFault leider nicht sehr viel aussagt, finde ich es durchaus angebracht. Ich habe den wohl offensichtlichen Fehler einfach nicht gesehen. Da hilft es, wenn mal schnell andere drüber schauen.

    doh! schrieb:

    Dafür sollte Dir jeder Professor die Hammelbeine langziehen!

    Falls Du dich hier auf Abschreiben des Codes beziehst, dann gebe ich dir Recht 🤡 .

    Vielen Dank
    LG, freakC++



  • freakC++ schrieb:

    Ah ok 🙂 Das wusste ich nicht. Gibt es dafür einen Grund? Immerhin erbe ich die Methode, sodass sie deklariert sein sollte. In Java ist das nicht nötig.

    C++ Code:

    class Base {
    public:
       virtual void foo() {}
    };
    
    class Derived : public Base {
    public:
       void foo() {}
    };
    

    Java:

    class Base {
      public void foo() {}
    }
    
    class Derived extends Base {
      public void foo() {}
    }
    

    Sieht fuer mich ziemlich identisch aus.



  • freakC++ schrieb:

    Ah ok 🙂 Das wusste ich nicht. Gibt es dafür einen Grund?

    Ja.

    freakC++ schrieb:

    Immerhin erbe ich die Methode, sodass sie deklariert sein sollte.

    Ja, schon irgendwie.
    Aber der Autor von Derived hat ein darüberhinausgehendes schutzwürdiges Interesse, nämlich, daß wenn er sie nicht in seiner Klasse deklariert, daß dann auch kein Fremder Hanselpansel irgendwann ankommen kann und sie für ihn definieren kann.

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    struct Airplane{
        virtual void fly();
    };
    void Airplane::fly(){
        cout<<"flieg flieg flieg\n";
    }
    
    struct Boeing:Airplane{
        //fly not redefined, because the default implemetaition
        //is ok
    };
    
    int main(){
        Boeing b;
        b.fly();
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    //found in boost/unstable/alquaida.hxx
    void Boeing::fly(){
        Airplane::fly();
        if(clock()==9/11)
            cout<<"crash crash crash\n";
    }
    

    freakC++ schrieb:

    In Java ist das nicht nötig.

    🤡



  • In C++ benutzt man für Strategy eher std::function oder so. Das ist einfacher als das Gefummel mit abtrakten Klassen.

    freakC++ schrieb:

    scheduler* test = new fifo(proc); //edit: Rechtschreibfehler verbessert
    vector<string> res = test->schedule(totalDuration); //Diese Methode verursacht den Fehler
    delete test;
    

    Das delete kannst du dir sparen und nie wieder benutzen. In diesem Fall kann das Beispiel ohne Speicherleck zum Beispiel so aussehen:

    fifo test(proc);
    vector<string> res = static_cast<scheduler &>(test).schedule(totalDuration);
    

    Wenn es wegen Polymorphie unbedingt new sein muss, verpackt man den Zeiger aus diversen Gründen in einem unique_ptr . Lies mal nach was RAII ist.

    unique_ptr<scheduler> test(new fifo(proc));
    test->schedule(totalDuration);
    

    Hat dein scheduler überhaupt einen virtuellen Destruktor? Wenn nicht ist das undefiniertes Verhalten beim delete .



  • Darum gehts nicht, fürchte ich.

    std::vector<std::string> scheduler::schedule(int duration) { 
        std::cout << "MamaScheduler" << std::endl; 
        scheduleAlgorithm(); //Aufruf der virtuellen Methode 
    }
    

    returnt nix.

    int main() {
    	vector<process> proc;
    	int totalDuration=100;
    
    	scheduler* test = new fifo(proc);
    	{
    		vector<string> res = test->schedule(totalDuration); //Diese Methode verursacht den Fehler indirekt
    		//res ist kaputt!
    		cout<<"noch lebt er"<<endl;
    		cin.get();
    		//res wird jetzt destruiert
    	}//Bumm
    	cout<<"jetzt ist er schon tot"<<endl;
    	delete test;
    	cin.get();
    }
    


  • freakC++ schrieb:

    Ah ok 🙂 Das wusste ich nicht. Gibt es dafür einen Grund? Immerhin erbe ich die Methode, sodass sie deklariert sein sollte. In Java ist das nicht nötig.

    Bis jetzt funktioniert alles soweit, doch mich quält ein Segmentation Error. Könnt ihr mal drüber schauen?

    class scheduler {
    
    	protected:
    		virtual void scheduleAlgorithm() = 0; //eine virtuelle Methode für die Kinder
    		std::vector<process> processes;	
    
    	public:
    		scheduler(std::vector<process> p) {processes = p;}
    		~scheduler(){};
    		std::vector<std::string> schedule(int);
    		
    
    };
    
    std::vector<std::string> scheduler::schedule(int duration) {
    
    	std::cout << "MamaScheduler" << std::endl;
    	scheduleAlgorithm(); //Aufruf der virtuellen Methode
    }
    
    class fifo : public scheduler{ //ein Kind von scheduler
    
    	public: 	
    		fifo(std::vector<process>);
    		~fifo(){}
    		void scheduleAlgorithm(); 
    };
    
    fifo::fifo(std::vector<process> p) : scheduler(p) {
    
    }
    
    void fifo::scheduleAlgorithm() {
    	std::cout << "Fifo-Algorithmus" << std::endl; //die virtuelle Methode wird definiert
    }
    

    In der main mache ich dann folgendes:

    scheduler* test = new fifo(proc); //edit: Rechtschreibfehler verbessert
    vector<string> res = test->schedule(totalDuration); //Diese Methode verursacht den Fehler
    delete test;
    

    Die Ausgabe erfolg nach meinen Erwartungen, doch danach kommt es zu einem Speicherzugriffsfehler:

    MamaScheduler
    Fifo-Algorithmus
    ./run.s: line 3: 5885 Segmentation fault ./scheduler "processes.txt"

    Ich arbeite mit keinen Zeigern (außer für "test"). Ich dachte, dass es irgendwie am Aufräumen liegt, doch den (sinnlosen) Destuktor rufe ich auf.

    Weiß jemand weiter?

    Vielen Dank
    LG, freakC++

    Drüberschauen hat nichts ergeben.

    Wir gehen aber auch nicht davon aus, daß Du Compilerwarnungen ignorierst oder abgeschaltet hast. Sowas pöses!

    Und hättest Du vollständigen Code gezeigt (Gerade groß genug, um lauffähig zu sein, ansonsten minimal, gerade mal den Fehler erzeugend bitte), hätte ich das schnell laden können und testen. So mußte ich erstmal eine Minute lang Drumherumsachen bauen, eine main(), Sachen includen und so. Dazu hatte ich natürlich wenig Lust, weshalb ich auch erstmal nicht antwortete.


Anmelden zum Antworten