dll, virtuelle klasse und zeigerübergabe. geht das so ?



  • danke 🙂

    aber ich kann über die funktionen der basisklasse (wenn sie im hauptprogramm entsprechend eingebunden wurden) auf die versteckten daten zugreifen - oder ?



  • Die Virtuellen Methoden werden in einer vtable deines Objekts zusammengefasst. Und wenn du per "test = new Intern;" dein Objekt anlegst, werden die Zeiger in der vtable auf die Methoden umgebogen, die du in der Intern-Klasse definiert hast.

    (bei den meisten Anwendungen geht es noch einen Schritt weiter - da besteht die Basis-Klasse nur aus abstrakten Methoden, bietet also noch nichtmal etwas eigenes an)



  • CStoll schrieb:

    Afaik gibt es damit keine Probleme. Nur solltest du vermutlich nicht versuchen, von der DLL aus dein Objekt zu delete'n.

    Warum sollte man aus der DLL das Objekt nicht löschen? Die einzige Voraussetzung ist, daß der Destruktor virtuell ist.

    Ich bin vor einigen Jahren mal über einen Bug im C++-Compiler von MS gestolpert (als ich noch Windows verwendet habe), wo man dynamischen Speicher, welcher in einer DLL oder dem Hauptprogramm angefordert hat, nicht in einer anderen frei geben konnte. Aber das war ein Bug und sollte schon lange behoben sein.

    Tntnet



  • tntnet schrieb:

    Ich bin vor einigen Jahren mal über einen Bug im C++-Compiler von MS gestolpert (als ich noch Windows verwendet habe), wo man dynamischen Speicher, welcher in einer DLL oder dem Hauptprogramm angefordert hat, nicht in einer anderen frei geben konnte. Aber das war ein Bug und sollte schon lange behoben sein.

    Genau deshalb meine Bemerkung - ich war mir nicht sicher, ob dieses Verhalten ein Bug oder gewollt war (und da bin ich lieber auf der sicheren Seite - wenn jeder sich um seinen Speicher selber kümmert, gibt es keine Zuständigkeitskonflikte).



  • CStoll schrieb:

    tntnet schrieb:

    Ich bin vor einigen Jahren mal über einen Bug im C++-Compiler von MS gestolpert (als ich noch Windows verwendet habe), wo man dynamischen Speicher, welcher in einer DLL oder dem Hauptprogramm angefordert hat, nicht in einer anderen frei geben konnte. Aber das war ein Bug und sollte schon lange behoben sein.

    Genau deshalb meine Bemerkung - ich war mir nicht sicher, ob dieses Verhalten ein Bug oder gewollt war (und da bin ich lieber auf der sicheren Seite - wenn jeder sich um seinen Speicher selber kümmert, gibt es keine Zuständigkeitskonflikte).

    Ist kein wirklicher Bug, das hängt damit zusammen, wie man die C-Runtime linkt.
    Wenn man die C-Runtime "Multithreaded DLL" linked, dann geht das mit der Freigabe Problemlos von beiden "Orten" aus, weil DLL und Programm dann denselben Speichermanager benutzen. Kompiliert man nur mit Multithreaded, dann muss man aufpassen, wobei wie schon erwähnt wurde, ein virtueller Destruktor hier hilfreich sein kann.



  • Der virtuelle Destruktor ist auf jeden Fall sinnvoll, egal mit welcher CRT-Option das Programm erstellt wurde 😉 (ohne den kannst du dich sogar ohne die DLL-Probleme in die Nesseln setzen - Base*ob=new Derived;...;delete op; gilt als undefined behaviour, wenn Base keinen virtuellen Dtor hat)



  • ich hab dazu jetzt nochmal eine frage:

    wenn ich den zeiger test, den ich ja vom hauptprogramm aus erhalten habe (aber in der dll durch die basisklasse nicht volständig bekannt ist nun wieder ans hauptprogramm zurückgebe.

    was kommt da an ? die basisklasse oder die interne klasse, die ursprünglich erzeugt wurde ?



  • Der Zeiger 'test' enthält nur eine Adresse, die irgendwohin in den Speicher zeigt. Dadurch, daß du diesen Zeiger herumreichst, ändert sich nichts am Inhalt des verzeigerten Speicherbereichs - ergo erhältst du das selbe Objekt von der DLL zurück, das du ihr gegeben hast.

    (und zur Laufzeit ist der Typ vollständig bekannt - und die DLL nutzt bei den virtuellen Methodenaufrufen halt den Code aus deinem Hauptprogramm)



  • danke!
    genau das wollte ich hören 🙂 🙂



  • ich will ja nicht nerven, aber nun bleibe ich wieder hängen :

    wenn ich vom hauptprogramm aus in der dll das objekt test (typ Basis) mit "new
    Intern" erzeugt habe, und ich aber nun von der dll aus den zeiger ans hauptprogramm zurückgeben will, gibt es wieder probleme.

    ich könne "Basis" nicht auf "Intern" casten. aber eigentlich ist doch der "Basis" pointer vom typ "Intern", dass weiss aber die dll nicht, weil der typ "Intern" in der dll ja unbekannt ist.

    was muss ich machen, damit ich im hauptprogramm wieder mit "Intern" arbeiten kann ?

    //Header in dll bekannt 
    class Basis 
    { 
    public: 
    lauter virtuelle funktionen... 
    }; 
    
    Basis *test; 
    
    //in dll nicht bekannt nur im hauptprogramm 
    class Intern : public Basis 
    { 
       die funktionen der basisklasse 
      und einen haufen variablen und pointer -> alle daten der klasse) 
    };
    


  • Das Hauptprogramm weiß, daß es ein Objekt vom Typ 'Intern' übergeben hat - aber von der DLL bekommt es ein 'Base'-Objekt zurück (von dem du als Programmierer weißt, daß es das reingegebene 'Intern'-Objekt ist - das Programm weiß das nicht). Um das wieder als 'Intern' verarbeiten zu können, mußt du es passend casten:

    Intern* returned_data = dynamic_cast<Intern*> DLL_getdata();
    if(returned_data==NULL)
    {
      cerr<<"das war das falsche Objekt\n";
    }
    else
    {
      //arbeite mit returned_data
    }
    


  • sagt mal, kann es sein, dass bei jeden "casten" der destructor aufgerufen wird ? ich habe in den destructor "MessageBox(..." eingefügt, um zu sehen, ob die funktion beim delete tatsächlich aufgerufen wird.
    nun kommt diese meldung aber immer, wenn ich die zeiger hin und her "caste" (was ziemlich oft passieren kann).



  • Nein, beim Casten wird eigentlich nichts destruiert. Aber eventuell hast du irgendwo lokale Kopien deines Objekts angelegt - die werden bei nächster Gelegenheit wieder beseitigt.

    (will sagen: zeig mal bitte etwas Code)



  • ich werde mal schauen, was ich zeigen kann, das problem ist, dass der soucecode mittlerweile auf 32 dateien verteilt ist und ich erst puzzlen muss, was für euch wichtig ist 😞

    Aber eventuell hast du irgendwo lokale Kopien deines Objekts angelegt -

    ähm ich dachte das geht nur mit new ?


Anmelden zum Antworten