Programm stürzt ab beim Zuweisen einer Variable



  • Welches reinterpret_cast<> meinst du?

    Die childs werden als UIElement erzeugt undzwar wie folgt:

    // im DialogProc:
    case WM_INITDIALOG: {
    	EnumChildWindows(_hWnd, EnumChildProc, reinterpret_cast<LPARAM> (this));
    } break;
    
    BOOL CALLBACK UIWindow::EnumChildProc(HWND hWnd, LPARAM lParam) {
    	UIWindow* window = reinterpret_cast<UIWindow*> (lParam);
    	UIElement* child;
    
    	child = new UIElement(hWnd, GetDlgCtrlID(hWnd), window);
    	window->_children += child;
    
    	return true;
    }
    

    Also Fakt ist, sie werden nicht als UIButton o.Ä. erzeugt, aber der Cast zu einem UIButton funktioniert.



  • DerCoder schrieb:

    Also Fakt ist, sie werden nicht als UIButton o.Ä. erzeugt, aber der Cast zu einem UIButton funktioniert.

    Du bist ein Held ...


  • Mod

    Damit wäre alles geklärt. Casts sind keine Magie. (Reinterpret-)Casts sagen dem Compiler nur: "Behandle dieses Objekt, als ob es in Wirklichkeit XYZ wäre, obwohl es für dich gerade wie ein ABC aussieht". Da wird nichts wirklich umgewandelt. Diese Casts sind die Methode des Programmierers zu sagen, dass er es ausnahmsweise besser weiß als der Compiler, weil der Programmierer irgendwelche Zusatzinformationen hat. Hier ist es wohl eher so, dass du keine Ahnung hast, was du da tust und den Compiler zum Schweigen bringst.

    Schritt für Schritt passiert folgendes:

    child = new UIElement(hWnd, GetDlgCtrlID(hWnd), window);
    

    Ein UIElement-Objekt wird erzeugt.

    ...
    window->getChild(IDC_SAVE)
    

    Du holst einen Zeiger auf dieses UIElement...

    ((UIButton*) window->getChild(IDC_SAVE))
    

    Hier sagst du dem Compiler, dass dieser Zeiger eigentlich auf einen UIBUtton zeigt, obwohl er wie ein Zeiger auf ein UIElement aussieht. Daher akzeptiert der Compiler den darauf folgenden Zugriff auf ein UIButton-Member:

    ((UIButton*) window->getChild(IDC_SAVE))->onClick
    

    Aber das onCLick ist gar nicht da, da getChild auf ein UIElement zeigt, das kein onClick hat. BUMM!

    Welches reinterpret_cast<> meinst du?

    Casts im C-Stil (also die mit den Klammern: (Typ)Variable , wie dein (UIButton*) window->getChild(IDC_SAVE) sind trickreich. Sie können je nach Kontext ein static_cast, ein const_cast oder ein reinterpret_cast oder gar eine Kombination aus mehrerem sein. Wenn man sich nicht verdammt gut auskennt, weiß man nie, was man bekommt. Und selbst wenn, dann kann eine kleine Änderung ganz woanders die Bedeutung total verändern. Also Finger weg! Außerdem sind sie nicht gut sichtbar und nicht durch einfache Textsuche im Quelltext findbar.

    Im Rest deines Quellcodes wimmelt es auch noch von mehr reinterpret_casts. Wie schon gesagt geht dadurch die Verantwortung voll auf den Programmierer über, dass alles seine Richtigkeit hat. Nichts für ungut, aber deine Sprachkenntnisse sind einfach noch nicht so weit, dass du solche Sachen tatsächlich besser weißt als der Compiler. Man kann und sollte lieber sauber programmieren, so dass man überhaupt nicht casten braucht. Da lernt man viel mehr und C++ spielt seine Stärke so richtig aus: Durch die strenge Typprüfung werden so nämlich sehr viele Logikfehler zu Typfehlern, so dass diese schon zur Compilezeit mit aussagekräfitger Fehlermeldung quittiert werden, anstatt dass man umständlich Laufzeitfehler (Abstürze) beheben muss.



  • Achso das hatte ich gar nicht bedacht 😞

    Kann ich denn irgendwie aus meinem UIElement ein UIButton machen? Also nachträglich? Sonst müsste ich nämlich beim Erstellen meines UIElement-Objekts prüfen, ob die Klasse des Childwindows (dess Button) == "Button" ist. Und das macht alles ziemlich langsam, oder?


  • Mod

    DerCoder schrieb:

    Sonst müsste ich nämlich beim Erstellen meines UIElement-Objekts prüfen, ob die Klasse des Childwindows (dess Button) == "Button" ist.

    Wieso?

    Mal ehrlich: Das Design scheint ziemlicher Murks zu sein, wenn obige Frage aufkommt. Du solltest erst einmal gründlich Erfahrung sowohl mit C++ als auch mit den bekannten Frameworks sammeln. Dann verstehst du auch, was die machen, wie die das machen und warum die das so machen. Wenn du dann immer noch den Wunsch verspürst, ein eigenes Framework zu schreiben (warum eigentlich? Was ist hier das Ziel?), dann kannst du dich viel besser auf dein eigentliches Ziel konzentrieren, anstatt mit den Grundlagen zu kämpfen.



  • Ohman, das deprimiert mich jetzt 😢 Ich programmiere schon seit 2 Jahren :c
    Ich möchte gern mein eigenes Framework benutzen, weil ich sonst den Überblick über die verfügbaren Funktionen verliere. Außerdem finde ich diese relativ kompakte Schreibweise in meiner main-Funktion besser, als wenn sie über 50 Zeilen verfügt. Und bei meinen kleinen Projekten habe ich gerne meine eigenen Klassen und Libs. Und außerdem lerne ich dadurch ja auch was ^^ Ich wär niemals auf das Problem mit den Casts gestoßen, hätte ich nicht diese Klassen geschrieben, oder?

    Hast du ne Idee, wie ich das auf meine Art hinkrieg?


  • Mod

    DerCoder schrieb:

    Hast du ne Idee, wie ich das auf meine Art hinkrieg?

    Dafür müsste ich mich erst einmal grundlegend in dein Framework hinein denken. Und wahrscheinlich würde ich dann sowieso alles ändern, was dann im Aufwand gleich wäre, mein eigenes Framework zu schreiben. Also eher nein 😞 .

    Fakt ist jedenfalls, wenn du einen UIButton willst, musst du einen UIButton erzeugen kein UIElement. Herbeizaubern geht nicht.



  • DerCoder schrieb:

    Ich wär niemals auf das Problem mit den Casts gestoßen, hätte ich nicht diese Klassen geschrieben, oder?

    Nachdem du dich mit Klassen/Objekten, Vererbung, Zeigern & Casts nicht wirklich auskennst, hättest du fürher oder später garantiert an anderer Stelle ein Problem mit Casts bekommen.

    Hast du ne Idee, wie ich das auf meine Art hinkrieg?

    Ganz einfach: du musst das erzeugen was du haben willst.
    Und nein, dadurch wird nicht alles furchtbar langsam. Computer sind ziemlich schnell.



  • hustbaer schrieb:

    Und nein, dadurch wird nicht alles furchtbar langsam.

    Ich meinte auch eher das auslesen der Klasse aus meinem HWND und das anschließende Vergleichen des Klassennamen mit "Button".



  • Vielleicht, vielleicht auch nicht. Vielleicht gibt es auch bessere Möglichkeiten, aber erstmal solltest du das Programm so umschreiben, dass es läuft und macht was es tut. Und zwar ohne casts. Wenn du dann Geschwindigkeitsprobleme haben solltest, kannst du das optimieren. Aber nur mal so: normalerweise wird es nicht langsamer, wenn du MEHR Typinformationen hinzufügst (UIElement? was ist das? Ohh, es ist vielleicht ein Button? dann muss ich prüfen ob es einer ist. vs: "hey, ein Button")

    Und ansonsten:

    First make it run, than make it fast.



  • DerCoder schrieb:

    hustbaer schrieb:

    Und nein, dadurch wird nicht alles furchtbar langsam.

    Ich meinte auch eher das auslesen der Klasse aus meinem HWND und das anschließende Vergleichen des Klassennamen mit "Button".

    Verstehe ich nicht. Wo willst du das machen? Und wieso soll etwas dadurch furchtbar langsam werden?



  • Im EnumChildWindowCallback folgendes machen (Pseudocode)

    klasse = GetWindowClassName(child)
    if (klasse == "Button")
      children += new UIButton(...)
    else if (klasse == "ComboBox")
      children += new UIComboBox(...)
    


  • Ja, sieht doch gut aus.
    Wo soll jetzt das Problem sein?
    Ängstigen dich die paar hundert oder tausend String-Vergleiche?
    Falls ja... probiers einfach mal, ich bin sicher dass du die Änderung nichtmal merkst.

    Und natürlich kann man das ganze auch noch weiter optimieren...

    LPCTSTR windowClass = GetWindowClassName(child);
    SomeIterator it = knownWindowClasses.find(windowClass); // Klasse in der map der bekannten Window-Klassen nachschlagen
    if (it != knownWindowClasses.end())
        children += it.second->factory->CreateObject(...); // Objekt über die Factory erzeugen lassen
    

    Wobei das vermutlich nicht wirklich viel schneller sein wird als die if-else-if Variante, vorausgesetzt du prüfst die am öftesten verwendeten Window-Klassen als erstes (Button, Label etc.).
    Dafür ist es übersichtlicher (und die Worst-Case Laufzeit ist auch besser).


Anmelden zum Antworten