dll's und interfaces
-
Mir wurde geraten, in einer dll eine abstrakte Klasse anzulegen, die überschrieben werden muss, anzulegen. Wie legt man denn in einer DLL eine Klasse an und wie kann man auf sie zugreifen? habt ihr eventuell tutorials? In meinem Windowsbuch (Windowsprogrammierung von Chrales Petzold) wird nur gezeigt wie dies mit Funktionen geht.
Welche Vorteile hat es überhaupt in einer dll ein Interface zu erstellen?
-
ungefähr so sollte dein header-file der dll aussehen, dass du dann ohne änderung in anderen projekten verwenden kannst.
die implementierung machst du wie immer ohne besonderheiten in einer *.cpp datei
#include <windows.h> #ifdef _CREATE_DLL #define __EXPORT __declspec(dllexport) #else #define __EXPORT __declspec(dllimport) #ifdef _DEBUG #pragma comment(lib,"debug\\my_lib") #else #pragma comment(lib,"release\\my_lib") #endif #endif class __EXPORT ccMyClass { private: protected: public: };
so far ... rocknix ///
ps: wie oft habe ich das eigentlich schon gepostet ? kann das nicht mal jemand in die FAQ schieben ???
[ Dieser Beitrag wurde am 14.05.2003 um 10:32 Uhr von RockNix editiert. ]
-
ach so:
_CREATE_DLL muss beim erstellen der DLL natürlich definiert sein - am besten in die DLL project-settings -> preprocessor packen, dann brauchste dich darum nicht mehr zu kümmern.
_DEBUG wird bei VC++ automatisch gesetzt.
rocknix ///
-
was sollen denn diese Praprozesserindirektiven?! wofür sind die gut? und warum sind überall so komische Striche?!
-
#include <windows.h> // dll wird erstellt mit "dllexport" #ifdef _CREATE_DLL #define __EXPORT __declspec(dllexport) #else // dll wird von project verwendet "dllimport" #define __EXPORT __declspec(dllimport) // lib wird automatisch an exe gelinkt #ifdef _DEBUG // debug lib linken #pragma comment(lib,"debug\\my_lib") #else // release lib linken #pragma comment(lib,"release\\my_lib") #endif #endif // klasse wird mit __EXPORT entsprechend behandelt ( s.o. ) class __EXPORT ccMyClass { private: protected: public: };
die unterstriche sind für "microsoft-geschädigte"
- beim __declspec müssen sie allerdings dran.
rocknix ///
[ Dieser Beitrag wurde am 14.05.2003 um 11:24 Uhr von RockNix editiert. ]
-
hier wird das aber ganz anders gemacht was ist denn nun richtig bzw. besser???
-
tja, so wie ich das auf den ersten blick gesehen habe, sparen die sich das direkte exportieren der klasse - was bedeutet, das von aussen kein direkter zugriff auf die klasse möglich ist - und lösen den zugriff über c-wrapper-funktionen. mit anderen worten, du brauchst dann für jeden zugriff 2 aufrufe. zum einen die wrapper funktion von aussen und intern dann den tatsächlichen zugriff.
die wrapper-funktionen müssen nach wie vor über directiven eingebaut werden - also kein unterschied.
vorteil ganz klar : dynamisches binden möglich, meine variante verlangt statisches binden via *.lib
nachteil ganz klar : calling overhead, der sich schon mal in sachen geschwindigkeit bemerkbar machen kann ( je nach anwendung - nix für RT )
rocknix ///
-
also einmal was sind "Wrapper-funktionen"
und dann was heisst RT?`
kannst mir das vielleicht erklären wie das da gemacht wird ? Ich verstehe zum Beispiel gar nicht warum die da nen Zeiger auf nen Zeiger verwenden usw.
-
RT = realtime, also echtzeitanwendungen
WRAPPER-FUNCTIONS sind funktionen die dem zweck dienen, eine andere funktionalität vor dem user zu verbergen. wenn du dir das beispiel auf der seite mal ansiehst, wirst du feststellen, das die mittels einer wrapper-function GetPlugIn() eine Instanz erzeugen. normalerweise würdest du dies schlicht und einfach per new() in deinem programm selber machen, was aber hier nicht funktioniert, da die klasse NICHT exportiert wird - mit anderen worten der instance-pointer wird NUR in der DLL gehalten, du kannst ihn ausserhalb nicht direkt verwenden. für die zugriffe werden dann sog. wrapper-funktionen verwendet. daher rührt auch der von mir angedeutete overhead.
rocknix ///
-
Wie oft hatten wir das schon? Klassen in dlls?
Klassen sollte man nicht aus DLLs exportieren. Dafür gibts andere, bessere Methoden.
Denn dadurch wird die DLLs stark compilerabhängig. Du musst für jeden Compiler, manchmal sogar für jede Compilerversion eine eigene DLL rausbringen.
Dafür gibt es die C-Wrapperfunktionen. Die sorgen dafür, dass die DLL compilerunhabängig wird.Merke: DLL-Funktionen dürfen nichts mit C++-Klassen am Hut haben. Weder in den Parametern noch im return-Wert. So schade es ist, aber folgendes ist nicht gut:
EXPORT std::string GetMessage() { return "Hello World"; }
Genauso ist es mit Exceptions. Eine Exception darf die DLL nie verlassen! Das wäre tödlich.
p.s.:
Auch für Präprozessordefinitionen gilt IMO die Regel: Doppelte führende Unterstriche sind immer verboten. Auf globaler Ebene sogar einfache führende Unterstriche. Da jedes #define global ist, darf man also gar keine führenden Unterstriche verwenden. Also nimm besser EXPORT als __EXPORT oder _EXPORT.
-
Original erstellt von cd9000:
Auch für Präprozessordefinitionen gilt IMO die Regel: Doppelte führende Unterstriche sind immer verboten. Auf globaler Ebene sogar einfache führende Unterstriche. Da jedes #define global ist, darf man also gar keine führenden Unterstriche verwenden. Also nimm besser EXPORT als __EXPORT oder _EXPORT.Begründung? (außer, dass es ohne __ besser aussieht)
-
wie sieht es denn mit Plugins aus? Es bietet sich doch da an, mit Interfaces zu arbeiten...
schaut mal auf dieses tutorial...auch wenn ich es nicht wirklich verstehe liegt wohl an den Funktionspointern....
-
__ ist für Compiler sachen
-
__ ist für Compiler sachen
genau deshalb sind sie in meiner header-datei auch drin
Klassen sollte man nicht aus DLLs exportieren. Dafür gibts andere, bessere Methoden.
und zwar welche ?
Dafür gibt es die C-Wrapperfunktionen. Die sorgen dafür, dass die DLL compilerunhabängig wird.
ja, mit einem berg von unnötigem overhead !
DLL-Funktionen dürfen nichts mit C++-Klassen am Hut haben
sehe ich nicht so, denn wenn ich für jede methode erst einmal eine wrapper-funktion schreiben muss, kann ich mir das auch gleich sparen - vom aufwand der verwealtung mal ganz abgesehen. bei einem singleton sicherlich noch einfach, erhöht sich der verwaltungskram bei mehrfach-instanzen um einiges. übrigens machen ms und borland ( mfc & vcl ) auch nichts anderes, als klassen exportieren, nur merkt der user dass für gewöhnlich nicht, da die libs von den project-settings automatisch mitgelinkt werden.
nene, hier einfach hinstellen und sagen "klassen export ist nicht" ist zu einfach. muss ja gestehen, dass ich mit dieser ganzen lib-linkerei auch nicht ganz glücklich bin, aber eine passable alternative habe ich noch nicht gefunden. leider ...
es gab mal einen artikel, in dem hat einer beschrieben, wie man klasse dynmisch aus einer dll lädt ( jaja, das geht ) - aber leider war das sowas von kompliziert und aufgebläht. naja, der hat das über die virtuelle methodentabelle gemacht.
so far ... rocknix ///
-
Ich kenn mich da zwar net so aus, aber meinst du sowas hier?!
@RockNix: Ist das jetzt fertig für die FAQ, oder soll ich noch warten?
-
Das COM rulet
-
@flenders: fertig für die FAQ war es eigentlich schon nach meinem beitrag mit dem beispiel, wie ein header aufgebaut wird, um eine klasse zu exportieren.
der rest ist eigenltich wieder die übliche "puristendiskussion"
so far ... rocknix
-
übrigens machen ms und borland ( mfc & vcl ) auch nichts anderes, als klassen exportieren, nur merkt der user dass für gewöhnlich nicht, da die libs von den project-settings automatisch mitgelinkt werden.
Und genau da liegt auch die Betonung: Man merkt es nicht. Und natürlich kommen die Borland-Werkzeuge nicht auf die Idee, die Runtimes von MS zu benutzen. Wenn die Dll aber von Dir selbst ist, merkst Du was von der Benutzung. Und da Du Dich entschlossen hast, eine Dll zu erstellen, unterstelle ich jetzt mal, daß Du sie auch in anderen Projekten nutzen und eventuell sogar mit anderen teilen möchtest. Und da geht das Problem los, Du mußt Dich jetzt ganz schön verbiegen. Und wenn dann noch Exceptions nach aussen treten, ist's ganz und gar vorbei.
Schau Dir doch als Alternative beispielsweise COM an. COM wird von allen gängigen Werkzeugen bestens unterstützt. Das Argument Verwaltungs-Aufwand zieht hier also nicht. Auch ist Geschwindigkeit kein Argument. Lediglich die Erzeugung des Objects dauert geringfügig länger, danach werden, sofern das Object im Apartment des Clients wohnt, die Methoden wie gewohnt aufgerufen. Der einzige Overhead, den es hier zu beklagen gibt, besteht aus drei zusätzlichen Methoden, die das Object bereitstellen muß.
es gab mal einen artikel, in dem hat einer beschrieben, wie man klasse dynmisch aus einer dll lädt ( jaja, das geht ) - aber leider war das sowas von kompliziert und aufgebläht. naja, der hat das über die virtuelle methodentabelle gemacht.
Genau so geht das in COM. Und das ist kein Stück kompliziert und aufgebläht, IMO. Ja, klar. Etwas mehr zu tippen ist's schon. Aber bedenke, was Du auf der anderen Seite gewinnst: Freie Werkzeug-Wahl.
So, mein Senf zum Thema.
[ Dieser Beitrag wurde am 16.05.2003 um 12:48 Uhr von -King- editiert. ]
-
der rest ist eigenltich wieder die übliche "puristendiskussion"
Oh, dann hätte ich mir meinen letzten Beitrag auch sparen können ...