a.exe funktioniert nicht mehr
-
Hallo allerseits,
Ich soll aus einem Array mit Instanzen der Klasse Figur und deren Subklassen den Index bestimmen, an dem sich die Figur mit der größten Fläche befindet.
Die Baumstruktur sieht wie folgt aus:
FIGUR
KREIS || RECHTECK
||||||||||||| QUADRATBis auf die Klasse Figur besitzen alle Klassen die Methode berechneFlaeche(), die die Fläche des Objektes ausgibt. Das Problem ist, dass bei direkten Instanzen der Klasse Figur die Funktion berechneFlaeche() einen Fehler ausgibt. Um herauszufinden, ob die jeweiligen Arrayelemente direkte Instanzen der Klasse Figur sind oder nicht, habe ich dynamic_cast verwendet.
Mein Code für die Suche nach dem Index sieht wie folgt aus:
int index=0; for(int i=0;i<sizeof(fig)-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++;} }Beim Kompilieren gibts keine Fehler/Warnungen.
Woran kann es liegen, dass das Programm abstürzt?LG
Markus
-
Häufig liegt es an einer Exception, die vom Betriebssytem abgefangen werden muss, weil der Programmierer es nicht gemacht hat.
Es gibt auch viele andere möglichen Gründe... Ist aber auch egal, du willst ja wissen, weshalb
deinProgramm abstürtzt, also zeig mal ein minimales Beispiel, das dein Problem zeigt.
-
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 einFigure 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 ArrayFigur*enthält.Figurist übrigens das Paradebeispiel für eine abstrakte (Basis-)Klasse. Wäre es nicht sinnvoll, wenn man keine Instanzen vonFigurerstellen 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(); }; #endifmain-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: --^