Erweiterbarkeit um neue Funktionen
-
Hallo,
wie würdet ihr so etwas konzeptionell angehen:
Ein Programm, das ein paar Standardfunktionen anbietet, soll auf möglichst einfache Weise um weitere Funktionen ergänzt werden, ohne jedoch dabei an zu vielen Stellen im bereits existierenden Programmcode Änderungen vornehmen zu müssen.
Ideal wäre so etwas wie eine Funktionsregistrierungsklasse (FRK) o. ä. der man die neue Funktion (die in eigenen Dateien .h/.cpp liegt) bekannt macht. Diese FRK wird im Hauptprogramm verwendet und stellt alle Funktionen zur Verfügung. Auf diese Weise müsste man am Hauptprogramm gar nichts ändern, sondern nur in der FRK.
Gibts dafür ein Muster o. ä.?
Danke für jeden gut gemeinten Rat!
-
Noch schöner wäre ein System über Plugins.
Infos z.B. http://www.nuclex.org/articles/building-a-better-plugin-architecture
-
Cool, danke schon mal, werde ich mir nachher mal in Ruhe durchlesen!
-
So, hab mir das mal durchgelesen. Wie es aussieht, ist der Einsatz des dort beschriebenen Plugin-Systems auf Windows-Systeme beschränkt, da DLL-Dateien verwendet werden. Wie könnte man so etwas denn möglichst portabel gestalten. Gibt es so etwas wie "plattformunabhängige DLLs"?

-
TheBrain schrieb:
So, hab mir das mal durchgelesen. Wie es aussieht, ist der Einsatz des dort beschriebenen Plugin-Systems auf Windows-Systeme beschränkt, da DLL-Dateien verwendet werden. Wie könnte man so etwas denn möglichst portabel gestalten. Gibt es so etwas wie "plattformunabhängige DLLs"?

Woran machst Du fest, dass das Tutorial auf Windows beschränkt ist? Dem ist nicht so. Steht sogar gleich im ersten Satz.
Das dynamische Bibliotheken nicht plattformunabhängig sein können, sollte wohl klar sein. Es sei denn, Du nimmst irgendwelche VMs als Plattform.
-
Das Prinzip ist immer das gleiche. Das einzige, was sich ändert, sind die Funktionen, um die Funktionen/Methoden der DLLs einzubinden. Und das ist wirklich kinderleicht:
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 # define DYNLIB_LOAD( a ) LoadLibraryEx( a, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ) # define DYNLIB_GETSYM( a, b ) GetProcAddress( a, b ) # define DYNLIB_UNLOAD( a ) !FreeLibrary( a ) struct HINSTANCE__; typedef struct HINSTANCE__* hInstance; #elif OGRE_PLATFORM == OGRE_PLATFORM_LINUX # define DYNLIB_HANDLE void* # define DYNLIB_LOAD( a ) dlopen( a, RTLD_LAZY | RTLD_GLOBAL) # define DYNLIB_GETSYM( a, b ) dlsym( a, b ) # define DYNLIB_UNLOAD( a ) dlclose( a )Hier mal ein Beispiel, wie es die Open-Source-3D-Engine Ogre macht.
Da nutzt man nur noch die Makros, um die zur Plattform passenden Funktionen auszuwählen.
-
Ok, habe ich das dann soweit richtig verstanden, dass ich für jedes unterstützte Betriebssystem eine entsprechende Datei benötige (für unixoide Systeme .so, für Windows .dll usw.)?
# define DYNLIB_LOAD( a ) LoadLibraryEx( a, NULL, LOAD_WITH_ALTERED_SEARCH_PATH )
Woher kommt hier eigentlich das a? Ich nehme an, es steht für eine Pfadangabe. Aber wo wird die konkretisiert? Kann ich dann im Code einfach irgendwo
DYNLIB_LOAD ("/path/to/my/dl")aufrufen?
Kennt ihr noch weitere gute Tutorials für ein solches Plugin-System bzw. für das Erstellen von dynamic libraries für mehrere OSe?
-
a ist in dem Fall stumpf der Parameter des Makros. Könnte auch Uwe dort stehen.

-
Ok, so weit, so gut. Es gibt einige Tutorials für Plugin-Architekturen unter C++ (z. B. dieses kurze hier). Allerdings gehen dabei alle davon aus, dass die Plugins eine bestimmte Funktion zur Verfügung stellen, die jeweils die gleichen Parameter und den gleichen Rückgabewert hat. Was jedoch, wenn ich Plugins mit unterschiedlich vielen Argumenten und verschiedenen Rückgabewerten umsetzen möchte? Wie geht man so etwas im "Hauptprogramm" am besten an?
-
TheBrain schrieb:
Allerdings gehen dabei alle davon aus, dass die Plugins eine bestimmte Funktion zur Verfügung stellen, die jeweils die gleichen Parameter und den gleichen Rückgabewert hat.
Anders wirst du Plugins auch schwerlich umsetzen können. Plugins sollen ja auch die Abhängigkeiten senken, man programmiert nicht gegen ein bestimmtes Plugin, sondern eine allgemeine Schnittstelle. Ggf. kann man auch mehrere Schnittstellen unterstützen, dann muss man aber jede separat behandeln.