a.exe funktioniert nicht mehr



  • Als Neuling in C++ weiß ich zwar, dass Exceptions durch try-catch-Strukturen funktionieren, jedoch kann ich leider den Tipp von dir nicht verwerten. Wie wird denn ein Exception vom Betriebssystem abgefangen und wie kann ich durch mein Code verhindern?



  • Markus97 schrieb:

    Wie wird denn ein Exception vom Betriebssystem abgefangen

    lol

    Markus97 schrieb:

    wie kann ich durch mein Code verhindern?

    Indem man auf dynamic_cast und Konsorten verzichtet.



  • Tut mir leid, was ich gepostet habe war auch nicht wirklich eine Lösung für dein Problem.

    Was mir ins Auge springt ist gleich deine Abbruchbedingung

    for(int i=0;i<sizeof(fig)-1;i++){
    

    Ist das wirklich was du willst? Du willst hier doch alle Elemente des Arrays von Figuren iterieren, bzw. bis das vorletzte Element, da du ja auch mit i+1 indexierst.

    Ich will mal folgendes minimale Beispiel zeigen:

    #include <iostream>
    
    int main()
    {
        const std::size_t a = 5;
        int arr[a];
        std::cout << "Anzahl der Elemente im Array: " << a << '\n'
                  << "sizeof(Array): " << sizeof(arr) << '\n'
                  << "sizeof(int): " << sizeof(int) << '\n';
    }
    

    In Anderen Worten: sizeof() liefert hier nicht die Anzahl der Elemente in deinem Array, sondern die Größe als Vielfaches von sizeof(char) ( == 1) (hui, hoff das ist so ok rausgedrückt, sonst gebt mir halt aufn Deckel)
    D.h. wenn du es mit sizeof machen willst, müsste es etwa so aussehen:

    i < sizeof(arr) / sizeof(Figur) - 1
    // was zum Problem wird, wenn du arr als Funktionsparameter übergeben willst.
    

    Oder du nimmst einfach std::array, dann hast du diese ganzen Probleme nicht, denn std::array kennt sein Größe. Siehe http://www.cplusplus.com/reference/array/array/



  • Oh ich dachte, dass man durch die Funktion sizeof direkt die Länge erhält, danke für den Tipp.

    Doch auch nach der Änderung stürzt das Programm leider ab:

    int index=0;
    	for(unsigned int i=0;i<(sizeof(fig)/sizeof(fig[0])) -1;i++){
    		//Berechnung der Fläche beim aktuellen Index
    		double f1;
    		Kreis* k1= dynamic_cast<Kreis*>(fig[i]);
    		Quadrat* q1=dynamic_cast<Quadrat*>(fig[i]);
    		Rechteck* r1=dynamic_cast<Rechteck*>(fig[i]);
    		if (q1!=0){f1=q1->berechneFlaeche();}
    		if (r1!=0){f1=r1->berechneFlaeche();}
    		if (k1!=0){f1=k1->berechneFlaeche();}
    		else{f1=0;}
    		double f2;
    		Kreis* k2= dynamic_cast<Kreis*>(fig[i+1]);
    		Quadrat* q2=dynamic_cast<Quadrat*>(fig[i+1]);
    		Rechteck* r2=dynamic_cast<Rechteck*>(fig[i+1]);
    		if (q2!=0){f2=q1->berechneFlaeche();}
    		if (r2!=0){f2=r1->berechneFlaeche();}
    		if (k2!=0){f2=k1->berechneFlaeche();}
    		else{f2=0;}
    		if (f2>f1){index++;}
    
    		}
    

    Wutze ich habe nach einer Funktion gesucht, die mir angibt, ob eine Instanz ein Element einer bestimmten Klasse ist oder nicht. Leider habe ich nichts gefunden, sodass ich dynamic_cast verwenden musste.



  • Ich versteh nicht, was Du da gemacht hast!?

    Das ist doch wohl eine Hierarchie à la

    struct figur{
      virtual double flaeche() const = 0;
      virtual ~figur() = default;
    };
    
    struct kreis : figur{
      kreis(double r) : r(r){}
      double flaeche() const { return 3.1415 * r * r; }
      double r;
    };
    
    struct rechteck : figur{
      rechteck(double b, double h) : b(b), h(h){}
      double flaeche() const { return b*h; }
      double b, h;
    };
    
    struct quadrat : rechteck{
      quadrat(double b) : rechteck(b,b) {}
    };
    

    Typisches Lehrbeispiel also. Oder nicht?



  • Sry aber was bringt mir jetzt dein Beispiel? Von der Hierarchie her ist es passend.



  • Markus97 schrieb:

    Sry aber was bringt mir jetzt dein Beispiel?

    LOL. Das ist genau der Trick dabei. Indem du dir Zeiger auf die Basisklasse figur hälst, musst du nie wissen, obs jetzt ein Rechteck, ein Kreis, oder sonst was ist. Du musst nur public ableiten, das hat Furble Wurble unterschlagen. dynamic_cast und alle anderen Varianten rauszufinden, obs eine Instanz einer Klasse ist, sind Mist, weil du damit deine Hierarchie nicht erweitern kannst. Jetzt schreibst du irgendwo noch eine Klasse Triangle, und schon musst du alle Stellen mit dem dynamic_cast anpassen. Genau deswegen gibts Ableitungen und Polymorphismus.



  • HarteWare schrieb:

    Ich will mal folgendes minimale Beispiel zeigen:

    #include <iostream>
    
    int main()
    {
        const std::size_t a = 5;
        int arr[a];
        std::cout << "Anzahl der Elemente im Array: " << a << '\n'
                  << "sizeof(Array): " << sizeof(arr) << '\n'
                  << "sizeof(int): " << sizeof(int) << '\n';
    }
    

    In Anderen Worten: sizeof() liefert hier nicht die Anzahl der Elemente in deinem Array, sondern die Größe als Vielfaches von sizeof(char) ( == 1) (hui, hoff das ist so ok rausgedrückt, sonst gebt mir halt aufn Deckel)

    Das Problem ist nur, was ist im Fall vom OP denn "fig"?
    Ist das ein

    Figure fig[n];
    

    oder ein

    Figure * fig = new Figure[n];
    // bzw
    Figure figs[n];
    //...
    Figure * fig = figs;
    

    Weil wenn du ein Array-to-Pointer-Decay dabei hast, dann klappt der Trick mit dem sizeof nicht mehr. Da wird dann rauskommen sizeof(pointertype)/sizeof(type).

    Abgesehen davon, dass ein Figure fig[n] auch gar nicht polymorph ist/sein kann.

    @Markus97: Zeig mal die Definition von fig.



  • //Erzeugung des Arrays mit den jeweiligen Figuren
    	Figur* fig[3];
    	fig[0]=new Figur(0,-1);
    	fig[1]=new Kreis(0,0,1);
    	fig[2]=new Rechteck(0,1,2,2);
    	fig[3]=new Quadrat(0,2,3);
    
        // Gebe die Figuren auf der Konsole aus.
        std::cout << fig[0]->asString() << std::endl;
        std::cout << fig[1]->asString() << std::endl;
        std::cout << fig[2]->asString() << std::endl;
        std::cout << fig[3]->asString() << std::endl;
    
    	int index=0;
    	for(unsigned int i=0;i<(sizeof(fig)/sizeof(fig[0])) -1;i++){
    		//Berechnung der Fläche beim aktuellen Index
    		double f1;
    		Figur* k1= dynamic_cast<Figur*>(fig[i]);
    		if (k1!=0){f1=0;}
    		else{f1=k1->berechneFlaeche();}
    		double f2;
    		Figur* k2= dynamic_cast<Figur*>(fig[i+1]);
    		if (k2!=0){f2=0;}
    		else{f2=k2->berechneFlaeche();}
    		if (f2>f1){index++;}
    
    		}
    

    Ich dachte, dass alle Elemente eines Arrays dieselbe Speichergröße beanspruchen.



  • Auch wenn der Trick mit sizeof nicht funktioniert und ich es stattdessen mit einer 2 austausche, stürzt das Programm leider ab.



  • Markus97 schrieb:

    Auch wenn der Trick mit sizeof nicht funktioniert und ich es stattdessen mit einer 2 austausche, stürzt das Programm leider ab.

    Geht aber schon in die richtige Richtung.

    ein Figur*[3] hat übrigens auch nur 3 Elemente (0,1 und 2).
    Und was soll der cast noch? Du weisst doch, dass das Array Figur* enthält.

    Figur ist übrigens das Paradebeispiel für eine abstrakte (Basis-)Klasse. Wäre es nicht sinnvoll, wenn man keine Instanzen von Figur erstellen kann? Z.b. weil man eh nix damit machen kann?
    Zeichnen? Was?
    Flaeche berechnen? Wie?



  • Ja, genau das müssen sie. In anderen Sprachen muss das nicht unbedingt so sein, aber da ist das auch hinter Abstraktion versteckt. z.B. unterstützt Java eben diese Co- bzw. Kontravarianzen.

    Zu deinem Programm:
    Wenn du das wirklich so geshcrieben hast, ohne Funktiosnaufruf zwischen den Figuren und der Schleife (sprich ohne, dass das Array zu einem pointer degeneriert) sollte das eigentlich klappen. Aber es geht auch besser.

    Dann dein dynamic_cast ist immer noch unnötig, denn dein "Objekt" ist eine Figur (oder Unterklasse, aber damit ists auf jedenfall eine Figur!), du musst nicht nochmal eine Figur draus machen.
    Der Nullcheck kann bleiben, aber prüf da gegen nullptr und nicht gegen 0.

    Das hier wäre ein Vorschlag wie das ganze etwas eifnacher gehen würde.

    std::vector<std::unique_ptr<Figure>> fig;
    //std::array<std::unique_ptr<Figure>, 4> fig; // egal ob std::vector doer std::array
    
    fig.push_back(std::make_unique<Figure>(0, -1));
    fig.push_back(std::make_unique<Kreis>(0,0,1));
    fig.push_back(std::make_unique<Rechteck>(0,1,2,2));
    fig.push_back(std::make_unique<Quadrat>(0,2,3));
    
    // Gebe die Figuren auf der Konsole aus.
    for(auto const& f : fig)
    	std::cout << f->asString() << std::endl;
    
    for(unsigned int i = 0; i < fig.size()-1; i++)
    {
    	double f1 = (fig[i] == nullptr) ? 0 : fig[i]->berechneFlaeche();
    	double f2 = (fig[i+1] == nullptr) ? 0 : fig[i+1]->berechneFlaeche();
    
    	if (f2>f1)
    		index++;
    }
    


  • ein Figur*[3] hat übrigens auch nur 3 Elemente (0,1 und 2).

    Stimmt, das habe ich übersehen. Leider stürzt die exe-Datei wieder ab.

    Figur ist übrigens das Paradebeispiel für eine abstrakte (Basis-)Klasse. Wäre es nicht sinnvoll, wenn man keine Instanzen von Figur erstellen kann? Z.b. weil man eh nix damit machen kann?
    Zeichnen? Was?
    Flaeche berechnen? Wie?

    Den Sinn dieser komischen Aufgabe hinterfrage ich erst garnicht 😃
    Laut Aufgabenstellung sollte ich es so programmieren.



  • Skym0sh0 danke für die Mühe. Ich würde es auch gerne mit Vektoren lösen, jedoch muss ich laut Aufgabenstellung ein Array verwenden.

    Eine 0 habe ich aus dem Grund verwendet, weil ich bei Nullpointern die Fehlermeldung "nullptr was not declared in this scope" erhalte.



  • Okay, was hast du für einen Compiler?
    Im (halbwegs) aktuellen MSVC ist nullptr drin und bei nem GCC Derivat musstes mit -std=c++11(oder so ähnlich) aktivieren.

    Hast du einen Debugger zur Hand? Wenn ja nutz ihn, dann siehst du wo es kracht (bzw solltest sehen).

    Und zeig mal am besten den gesamten Quellcode, wenn er denn die paar hundert Zeilen nicht übersteigt.



  • Wie gesagt, es gibt auch std::array, und wenn das dir verboten wird, dann würde ich aber mal nach einem guten Grund fragen, denn es ist im Prinzip ein C-Style Array, aber besser (Es gibt glaub manche die meinen, das C-Style Array wäre schneller, mag sein, weiß nicht, aber das ist in diesem Fall wohl nicht von Bedeutung).

    Übrigens, für nullptr musst du glaub C++11 "aktivieren". (googeln)

    @Skym0sh0:
    "array-to-pointer-decay" Danke, genau so ein Begriff hat mir gefehlt 😃
    Ich wollte in meinem Beispiel auch eigentlich verdeutlichen, dass man da das "a" verwenden soll, also die eigentliche Größe, um eben solchen Problemen zuvorzukommen.

    Ich will noch anmerken, dass solche "asString" "toString" methoden auch nicht gerade C++-like sind. Wozu kann man den << Operator überladen.
    Und wirklich komplizierter ist das auch nicht, wenn man schon so eine toString Funktion hat.



  • Ich kompiliere die Codes mit dem Befehl g++ -Wall .cpp.
    Als Kompilierer verwende ich mingGW.
    Hier der Code für die Basisklasse:
    cpp:

    #include "figur.hpp"
    
    Figur::Figur(double pos_x, double pos_y)
      : pos_x(pos_x), pos_y(pos_y){}
    
    Figur::~Figur(){}
    
    void Figur::verschiebe(double dx, double dy)
    {
      pos_x += dx;
      pos_y += dy;
    }
    
    std::string Figur::asString()
    {
      return "Dies ist eine Figur. Koordinaten: ("
        + std::to_string(pos_x) + "," + std::to_string(pos_y) + ")";
    }
    

    hpp:

    #ifndef FIGUR_HPP
    #define FIGUR_HPP
    
    #include <string>
    #include "tostring.hpp"
    
    class Figur
    {
    protected:
      // Attribute
      double pos_x;
      double pos_y;
    
    public:
      // Konstruktor
      Figur(double pos_x, double pos_y);
      //Destruktor
      virtual ~Figur();
      // Verschiebt die Figur um dx in x-Richtung und um dy in y-Richtung.
      void verschiebe(double dx, double dy);
      // Gibt einen den die Figur beschreibenden String zurueck.
      virtual std::string asString();
    };
    
    #endif
    

    main-Datei:

    #include <iostream>
    
    /* Das Einbinden der Header-Dateien wuerde 
     * ohne Include-Guards zum mehrfachen Einbinden
     * der selben Header-Datei (z.B. figur.hpp) fuehren. 
     */
    #include "figur.hpp"
    #include "kreis.hpp"
    #include "rechteck.hpp"
    #include "quadrat.hpp"
    
    int main()
    {
    
    	//Erzeugung des Arrays mit den jeweiligen Figuren
    	Figur* fig[4];
    	fig[0]=new Figur(0,-1);
    	fig[1]=new Kreis(0,0,1);
    	fig[2]=new Rechteck(0,1,2,2);
    	fig[3]=new Quadrat(0,2,3);
    
        // Gebe die Figuren auf der Konsole aus.
        std::cout << fig[0]->asString() << std::endl;
        std::cout << fig[1]->asString() << std::endl;
        std::cout << fig[2]->asString() << std::endl;
        std::cout << fig[3]->asString() << std::endl;
    
    	int index=0;
    	for(unsigned int i=0;i<2;i++){
    		//Berechnung der Fläche beim aktuellen Index
    		double f1;
    		Kreis* k1= dynamic_cast<Kreis*>(fig[i]);
    		Quadrat* q1=dynamic_cast<Quadrat*>(fig[i]);
    		Rechteck* r1=dynamic_cast<Rechteck*>(fig[i]);
    		if (q1!=0){f1=q1->berechneFlaeche();}
    		if (r1!=0){f1=r1->berechneFlaeche();}
    		if (k1!=0){f1=k1->berechneFlaeche();}
    		else{f1=0;}
    		double f2;
    		Kreis* k2= dynamic_cast<Kreis*>(fig[i+1]);
    		Quadrat* q2=dynamic_cast<Quadrat*>(fig[i+1]);
    		Rechteck* r2=dynamic_cast<Rechteck*>(fig[i+1]);
    		if (q2!=0){f2=q1->berechneFlaeche();}
    		if (r2!=0){f2=r1->berechneFlaeche();}
    		if (k2!=0){f2=k1->berechneFlaeche();}
    		else{f2=0;}
    		if (f2>f1){index++;}
    
    		}
        // Verschiebe Figuren
        fig[0]->verschiebe(10,10);
        fig[1]->verschiebe(10,10);
        fig[2]->verschiebe(10,10);
        fig[3]->verschiebe(10,10);
    
        // Gebe die Figuren auf der Konsole aus
        std::cout << fig[0]->asString() << std::endl;
        std::cout << fig[1]->asString() << std::endl;
        std::cout << fig[2]->asString() << std::endl;
        std::cout << fig[3]->asString() << std::endl;
    
        // Bereinige Speicher.
        delete fig[0];
        delete fig[1];
        delete fig[2];
        delete fig[3];
    
    }
    


  • Klassischer copy/paste-Fehler:

    if (q1!=0){f1=q1->berechneFlaeche();}
    if (r1!=0){f1=r1->berechneFlaeche();}
    if (k1!=0){f1=k1->berechneFlaeche();}
    else{f1=0;}
    double f2;
    Kreis* k2= dynamic_cast<Kreis*>(fig[i+1]);
    Quadrat* q2=dynamic_cast<Quadrat*>(fig[i+1]);
    Rechteck* r2=dynamic_cast<Rechteck*>(fig[i+1]);
    if (q2!=0){f2=q1->berechneFlaeche();}
    if (r2!=0){f2=r1->berechneFlaeche();}
    if (k2!=0){f2=k1->berechneFlaeche();}
    //     hier: --^
    


  • In der Zukunft sollte ich lieber konzentrierter den Code durchgehen bevor ich hier um Hilfe bitte 🙄 🙄 🙄
    Danke für die Fehlersuche 👍



  • Markus97 schrieb:

    main-Datei:

    #include <iostream>
    
    /* Das Einbinden der Header-Dateien wuerde 
     * ohne Include-Guards zum mehrfachen Einbinden
     * der selben Header-Datei (z.B. figur.hpp) fuehren. 
     */
    #include "figur.hpp"
    #include "kreis.hpp"
    #include "rechteck.hpp"
    #include "quadrat.hpp"
    
    int main()
    {
      
    	//Erzeugung des Arrays mit den jeweiligen Figuren
    	Figur* fig[4];
    	fig[0]=new Figur(0,-1);
    	fig[1]=new Kreis(0,0,1);
    	fig[2]=new Rechteck(0,1,2,2);
    	fig[3]=new Quadrat(0,2,3);
    
        // Gebe die Figuren auf der Konsole aus.
        std::cout << fig[0]->asString() << std::endl;
        std::cout << fig[1]->asString() << std::endl;
        std::cout << fig[2]->asString() << std::endl;
        std::cout << fig[3]->asString() << std::endl;
    	
    	
    	
    	int index=0;
    	for(unsigned int i=0;i<2;i++){
    		//Berechnung der Fläche beim aktuellen Index
    		double f1;
    		Kreis* k1= dynamic_cast<Kreis*>(fig[i]);
    		Quadrat* q1=dynamic_cast<Quadrat*>(fig[i]);
    		Rechteck* r1=dynamic_cast<Rechteck*>(fig[i]);
    		if (q1!=0){f1=q1->berechneFlaeche();}
    		if (r1!=0){f1=r1->berechneFlaeche();}
    		if (k1!=0){f1=k1->berechneFlaeche();}
    		else{f1=0;}
    		double f2;
    		Kreis* k2= dynamic_cast<Kreis*>(fig[i+1]);
    		Quadrat* q2=dynamic_cast<Quadrat*>(fig[i+1]);
    		Rechteck* r2=dynamic_cast<Rechteck*>(fig[i+1]);
    		if (q2!=0){f2=q1->berechneFlaeche();}
    		if (r2!=0){f2=r1->berechneFlaeche();}
    		if (k2!=0){f2=k1->berechneFlaeche();}
    		else{f2=0;}
    		if (f2>f1){index++;}
    		
    		}
        // Verschiebe Figuren
        fig[0]->verschiebe(10,10);
        fig[1]->verschiebe(10,10);
        fig[2]->verschiebe(10,10);
        fig[3]->verschiebe(10,10);
    
        // Gebe die Figuren auf der Konsole aus
        std::cout << fig[0]->asString() << std::endl;
        std::cout << fig[1]->asString() << std::endl;
        std::cout << fig[2]->asString() << std::endl;
        std::cout << fig[3]->asString() << std::endl;
    
        // Bereinige Speicher.
        delete fig[0];
        delete fig[1];
        delete fig[2];
        delete fig[3];
    }
    

    Ähm...jetzt bin ich baff...

    Bist Du sicher dass Du die Aufgabe richtig verstanden hast? Gibt es dazu einen Lehrer oder Prof, bei dem Du nachfragen kannst?

    Und noch eins:

    // Gebe die Figuren auf der Konsole aus
        std::cout << fig[0]->asString() << std::endl;
        std::cout << fig[1]->asString() << std::endl;
        std::cout << fig[2]->asString() << std::endl;
        std::cout << fig[3]->asString() << std::endl;
    

    Kennst Du einen Mechanismus in C++, der ohne copy&paste einen Programmabschnitt x-mal wiederholt?


Anmelden zum Antworten