Virtuelle Funktion in einer von einer abstrakten Klasse abgeleitetetn Klasse in einer DLL
-
Hallo, ich habe folgendes Problem : Um eine Klasse und deren Methoden aus einer
DLL exportieren zu können, habe ich eine abstrakte Klasse benutzt. In meiner Anwendung erzeuge ich dann eine neue Klasse, die von der abstrakten abgeleitet ist. Über eine Funktion CreateInstance beschaffe ich mir ein Objekt der Klasse aus der DLL. Normale Methoden der DLL-Klasse kann ich dann problemlos aufrufen. Sind die Funktionen aber in der DLL als virtuell deklariert und ich möchte sie in meiner Anwendungsklasse überschreiben, wird der Code nicht ausgeführt. Funktioniert das generell nicht.
Anbei noch der Code eines Beispiels für mein Problem :Inhalt der DLL
Dllmain.h #ifdef __dll__ # define DLLIMPORT __declspec (dllexport) #else # define DLLIMPORT __declspec (dllimport) #endif #include <stdio.h> class VStack { public: virtual void Push(char) = 0; virtual char Pop(void) = 0; virtual unsigned long Size(void) = 0; virtual void Test(void) =0; }; void VStack::Test(void){;} extern "C" VStack* DLLIMPORT CreateClassInstance(); dllmain.cpp #pragma argsused #define __dll__ #include "Dllmain.h" #include <windows.h> class Knoten { friend class Stack; private: Knoten *next; char data; }; class Stack : public VStack { public: Stack(); //~Stack(void); void Push(char); char Pop(void); unsigned long Size(void); virtual void Test(); // PROBLEMFUNKTION !!!!! private: Knoten *root; unsigned long anz; }; Stack::Stack() { root=NULL; anz=0; } /*Stack::~Stack(void) { Knoten *cur=root,*next; while(root) { next=cur->next; delete(cur); cur=next; } }*/ void Stack::Push(char d) { if(root==NULL) { root=new(Knoten); root->next=NULL; root->data=d; anz++; } else { Knoten *head=new(Knoten); head->next=root; head->data=d; root=head; anz++; } } char Stack::Pop(void) { if(root!=NULL) { char d = root->data; root=root->next; anz--; return d; } return NULL; } unsigned long Stack::Size() { return anz; } void Stack::Test(){}; extern "C" VStack* DLLIMPORT CreateClassInstance() { return ((VStack*)(new Stack)); } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved) { return 1; }ANWENDUNG //--------------------------------------------------------------------------- #pragma hdrstop #include <iostream.h> //--------------------------------------------------------------------------- #pragma argsused #include "Dllmain.h" // Meine Klasse von der abstrakten Klasse abgeleitet, die virtuelle Methode // Test aus der Klasse Stack (in der DLL) möchte ich überschreiben class CTest : public VStack { public : void Test(void);}; void CTest::Test(void){ cout << "\nAusgabe aus der internen virtuellen Funktion\n"; } int main(int argc, char* argv[]) { int n; VStack* PointerToClass = NULL; CTest* Pointer = NULL; PointerToClass = (VStack*)CreateClassInstance(); Pointer = (CTest*)CreateClassInstance(); cout << "Objektklasse geladen!\nWieviele Elemente (char) wollen Sie auf dem Stapel legen? n="; cin >> n; char ch; for(int i=0;i<n;i++) { cin >> ch; PointerToClass->Push(ch); } cout << "\nAusgabe der Elemente vom Stapel:\n"; for(int i=0;i<n;i++) { cout << PointerToClass->Pop() << " "; } PointerToClass->VStack::Test(); // FUNKTIONIERT NICHT Pointer->Test(); // WIRD NICHT AUSGEFÜHRT !!!!!!!!!!!!! cout << "\n\n"; cout << "bitte zum Beenden eine Zahl eingeben \n"; cin >> n; delete(PointerToClass); return 0; }ich suche schon seit Wochen nach einer Lösung, wichtig ist ,dass die Methode in der DLL virtuell ist ! HILFE !!
/Edit : Cpp-Tags
-
Hallo
"extern C" und C++ Klassen vertragen sich nunmal nicht. Du must dich für das DLL-Interface zwischen zwei Optionen entscheiden :
- einem reinem C-Interface ohne Klassen. Das erlaubt die DLL auch von anderen Compilern und Sprachen auch zu benutzen. Hier darfst du aber in keinem Fall bei den zu exportierenden Funktionen mit C++ Datentypen arbeiten. Ich bezweifle das dein gezeigtes Casten wirklich gültig ist, auch wenn es kompiliert und bei dir funktioniert- einem C++ Interface mit Klassen. Hier ist alles an C++ Eigenheiten erlaubt, auch virtuelle Methoden. Dazu must du aber die gesamte Klasse dexportieren
class DLLIMPORT VStack // Hier den Modifikator einfügen { public: virtual void Push(char) = 0; virtual char Pop(void) = 0; virtual unsigned long Size(void) = 0; virtual void Test(void) =0; };und du brauchst auch keine CreateInstance-Methode die ohne eine äquivalente DestroyInstance-Methode sowieso gefährlich ist (new von DLL aufrufen lassen und delete von Hauptmodul)
Nachteil : Diese DLL kann ausschließlich von Projekten verwendet werden die mit dem selbem Compiler erstellt werden wie auch die DLL. Das kann sogar die Version des Compilers betreffen.Und bitte beim nächsten Posten von Quellcode hier im Forum beachten : sfds
bis bald
akari
-
Hallo akari,
vielen Dank für die Antwort. Leider ist mein Anliegen genau das befürchtete.
Ich möchte die Borland-DLL von MS-VisualC++ aus aufrufen. Der Inhalt der DLL
ist ein umfangreiches Programmpaket zur Simulation und Modellierung Dynamischer Systeme mit diversen Klassen. Alles in Standard C umschreiben zu müssen wäre eine Katastrophe. Von Borland zu Borland habe ich eine DLL in der ich die Klasse
komplett exportiere (funktioniert mit BC++5,BC++6 und CodeGear C++Builder 7.0)
soll jetzt aber auch unter VisualC++ laufen !
Vielleicht weiss noch jemand einen Tip !?
-
Benötigst du die Klasse in der VC++ Anwendung direkt?
In deinem Fall bleibt dir wirklich nichts anderes übrig als ein reines C-Interface für die Dll zu verwenden. Du kannst ja Funktionen exportieren, die alle Berechnungen etc. innerhalb der dll kapseln. Die Daten, die dann die VC++Anwendung braucht müssen auch über diese Funktionen weitergegeben werden.
-
Hallo
Okay es gibt noch eine dritte Option :
Sprach- und Compilerunabhängige DLLs mit OOP-Interface kannst du unter Windows mit COM hinbekommen, aber auch das erfordert einen Umbau bzw. Wrapper für den bestehenden Code. Ist also auch sehr aufwändig.bis bald
akari
-
Hallo zurück,
ich bin gerade dabei mich mit wxwidgets zu beschäftigen. Wahrscheinlich werde ich das benutzen, gibts dazu ein Forum ?
Gruß und vielen Dank Katja
-
akari schrieb:
und du brauchst auch keine CreateInstance-Methode die ohne eine äquivalente DestroyInstance-Methode sowieso gefährlich ist (new von DLL aufrufen lassen und delete von Hauptmodul)
Das habe ich mich kürzlich auch gefragt, aber in der Praxis scheint es kein Problem zu sein, wenn die Klasse einen virtuellen Destruktor hat, da dann dieser den Speicher freigibt.
akari schrieb:
Nachteil : Diese DLL kann ausschließlich von Projekten verwendet werden die mit dem selbem Compiler erstellt werden wie auch die DLL. Das kann sogar die Version des Compilers betreffen.
... so daß nur das erwähnte COM bleibt, das ich hier außerdem gar nicht mal für eine schlechte Idee halte.
Für wxWidgets gibt es, auch wenn es hiermit irgendwie nichts zu tun hat, natürlich auch ein Forum und auch Binaries für C++Builder.
-
Ja, gibt es hier. Schau einfach mal in die Forenübersicht oder hier rein
http://www.c-plusplus.net/forum/viewforum-var-f-is-51.html