void* in ursprüngliche abgeleitete klasse casten


  • Administrator

    camper schrieb:

    Ich mache durchaus nicht weniger Fehler als andere. Ich versuche aber, die Fehler anderer nicht zu wiederholen.

    Du machst vergleichsweise allerdings wenig Fehler. Um ehrlich zu sein, habe ich bisher in diesem Forum von dir noch keinen gesehen 🙂
    Zudem habe ich wohl wegen meinem Vater, welcher vergleichsweise auch wenig Fehler macht, irgendwo einen Komplex, dass ich mich bei solchen Personen immer wieder extrem darüber freue, wenn sie Fehler machen. 😃

    camper schrieb:

    Das ändert nichts. Wenn man die Funktion nicht ändern kann, ruft man eben eine andere auf, d.h. einen Wrapper mit hinreichend restriktiven - also typsicherem Interface. void* ist grundsätzlich nur in zwei Situation sinnvoll. Einmal wenn man - aus welchen Gründen auch immer - einen Zeiger in einem generischen Typen speichern muss, sofern der Wert in den exakt gleichen Zeigertyp zurückkonvertiert werden kann. Zweitens für bestimmte low-level-Operationen (man denke an memcpy&co). Beides trifft hier nicht zu, folglich hat die vorgestellte Funktion keine Daseinsberechtigung sowohl als framework-spezifische Funktion als auch direkt aufzurufendes Interface zu dienen.

    Wenn du einen Wrapper oder was auch immer machst, irgendwo und irgendwann musst du die Funktion aufrufen. Das ändert nichts an der Tatsache, dass du die Finger von der Funktion lassen musst. Wahrscheinlich ist hier eine Callback Funktion definiert, welche erwartet wird, à la:

    void (*Func)(void*) callback;
    

    Und nicht jeder wird nun auch gleich einer C++ Wrapper für jede C-Bibliothek erstellen, obwohl es natürlich eigentlich zu empfehlen wäre 😉

    Zur Sache mit den Zeigern, dass wusste ich wirklich nicht. Bisher wurde mir in jeglichem Buch erklärt, dass sich die Objekte einfach hintereinander auf den Speicher legen und somit die gleiche Adresse haben. Also veranschaulicht:

    | Object der Klasse A | Objekt der Klasse B (erbt von A) |
    |---------------------|----------------------------------|
    | x Bytes ...         | y Bytes ...                      |
    |---------------------|----------------------------------|
    

    Aber man lernt ja bekanntlich nie aus 🙂
    Es kam bei mir aber auch noch nie soweit, dass ich das irgendwie benötigt hätte. Habe glaub ich noch nie von einer abgeleiteten Klasse auf void* und dann zurück auf eine Basis rumgereicht. Das wäre mir persönlich schon einfach nur vom Ansehen her, zu grässlich gewesen.

    Die Lösung von dem wäre dann aber ziemlich einfach:

    c_style_function(static_cast<Base*>(&child));
    

    camper schrieb:

    Dravere schrieb:

    Das Problem liegt allerdings immer noch am Aufruf von c_style_callback(this); im Base-Konstruktor! Vor allem dann, wenn das Child-Objekt in der main Funktion gebaut wird. Da wird dann die falsche Funktion aufgerufen.

    Und auch hier wiederspreche ich.

    Das freut mich! 😃

    camper schrieb:

    Die aufgerufene Funktion ist die Version der Basisklasse, klar. Ob das allerdings ein Fehler ist, kannst du nur dadurch herausfinden, indem du es mit der Intention des Programmierers vergleichst.

    Und da liegt dein Fehler! Wir wissen was die Intention des Programmierers ist, darf ich vorstellen:

    PaulM schrieb:

    Das verhält sich bei einem Aufruf der Art c_style_function( child ) nicht wie erwünscht, da immer Base::do_it() aufgerufen wird. Wie kann ich es am schönsten hinkriegen, dass immer die zur Klasse entsprechende virtuelle Funktion aufgerufen wird?

    Wie du dann im weiteren Satz auch sagst:

    camper schrieb:

    Der möchte, das immer die Version der abgeleiteten Klasse aufgerufen wird, und das ist nat. im Basisklassenkonstruktor unmöglich. Nicht aber das virtuell ist hier das Problem - sondern die Tatsache, das kein abgeleitetes Objekt existiert. Schließlich darf auch eine nicht-virtuelle nicht-statische Funktion der abgeleiteten Klasse nicht mit diesem noch zu konstruierenden Objekt aufgerufen werden.

    Und ich habe gesagt:

    Dravere schrieb:

    PaulM schrieb:

    Und da der Konstruktor nicht virtuell ist, ist this vom Typ (Base)*

    Das ist aber nicht das tatsächliche Problem! Das Problem hier ist, dass Child noch gar nicht konstruiert wurde.

    Es tut mir leid, aber es ist und bleibt der tatsächliche Fehler.

    Das andere mit dem c_style_function(&child); kommt ursprünglich nicht vom Threadersteller sondern von jemand anderem als Beispiel:
    http://www.c-plusplus.net/forum/viewtopic-var-p-is-1597813.html#1597813

    Ich weiss es nun und du wusstest es schon lange, dass dies zwar falsch ist, hat aber mit dem ursprünglichen und tatsächlichen Fehler nichts zu tun.

    (Was für ein Drama ich hier mache 🤡)

    Grüssli



  • camper schrieb:

    Vielmehr solltest du dir die Frage stellen - warum du dir überhaupt bei solchen Highlevel-konstrukten Gedanken über die Niederungen des Objektlayouts gedanken machen solltest/müsstest. Diese Durchbrechung von Abstraktionsebenen ist oft der Ausgangspunkt böser wtfs.

    Damit triffst du den Nagel auf den Kopf. 👍 Über den letzten Satz musste ich schon etwas lachen (auch wenn er natürlich stimmt). 😃


Anmelden zum Antworten