Poco::ClassLoader を紹介します。
Poco::ClassLoader クラスは、Shared Library から C++ のクラスを実行時に動的にロードします。ロードされるクラスは、その基底クラスとしてインスタンス化しなければいけません。Shared Library からロード可能なクラスにするためには、Shared Library は自身が含む全てのクラスに対して manifest を提供しなければいけません。ヘッダファイル “Foundation/ClassLibrary.h” のマクロを使えば、簡単に manifest を作ることができます。
POCO の 1.3 から、Shared Library は複数の manifest を export できるようになりました。デフォルトの無名 manifest に加え、異なる基底クラスを持つ複数の名前付き manifest を export することができます。
1つの Poco::ClassLoader インスタンスは、1つの manifest しかロードできないという制限があることに注意してください。
Plugin.h
#ifndef PLUGIN_H #define PLUGIN_H class Plugin { public: Plugin() {} virtual ~Plugin() {} virtual std::string name() const = 0; }; #endif // PLUGIN_H |
Plugin.cpp
・これを libPlugin という名前の SharedLibrary としてビルド。
#include <Poco/ClassLibrary.h> #include <string> #include <iostream> #include "Plugin.h" class PluginA : public Plugin { public: PluginA() {} ~PluginA() {} std::string name() const { return std::string("PluginA"); } }; class PluginB : public Plugin { public: PluginB() {} ~PluginB() {} std::string name() const { return std::string("PluginB"); } }; class PluginC : public Plugin { public: PluginC() {} ~PluginC() {} std::string name() const { return std::string("PluginC"); } }; POCO_BEGIN_MANIFEST(Plugin) POCO_EXPORT_CLASS(PluginA) POCO_EXPORT_CLASS(PluginB) POCO_EXPORT_SINGLETON(PluginC) POCO_END_MANIFEST void pocoInitializeLibrary() { std::cout << "Plugin initializing" << std::endl; } void pocoUninitializeLibrary() { std::cout << "Plugin uninitialzing" << std::endl; } |
ClassLoaderTest.cpp
・libPlugin という名前の SharedLibrary をロード。
・POCO_EXPORT_CLASS と宣言した PluginA, PluginB は create() でインスタンス化。
・POCO_EXPORT_SINGLETON と宣言した PluginC は instance() でインスタンス化。
・各 Plugin の name() を呼んで結果を表示。
#include <Poco/Format.h> #include <Poco/ClassLoader.h> #include <string> #include "ScopedLogMessage.h" #include "PrepareConsoleLogger.h" #include "../Plugin/Plugin.h" const std::string kSharedLibraryName("libPlugin"); const std::string kPluginNameA("PluginA"); // Note that PluginA is declared as POCO_EXPORT_CLASS in manifest const std::string kPluginNameB("PluginB"); // Note that PluginB is declared as POCO_EXPORT_CLASS in manifest const std::string kPluginNameC("PluginC"); // Note that PluginC is declared as POCO_EXPORT_SINGLETON in manifest const std::string kPluginNames[] = { kPluginNameA, kPluginNameB, kPluginNameC }; const std::size_t kNumPlugin = sizeof(kPluginNames)/sizeof(kPluginNames[0]); void TestClassLoader( ScopedLogMessage& msg , Poco::ClassLoader<Plugin>& cl , const std::string& pluginName) { if(cl.canCreate(pluginName)) { Plugin* pPlugin = cl.classFor(pluginName).create(); msg.Message(Poco::format(" %s created.", pPlugin->name())); delete pPlugin; } try { Plugin& plugin = cl.instance(pluginName); msg.Message(Poco::format(" %s instanciated.", plugin.name())); } catch(Poco::InvalidAccessException& exc) { msg.Message(" Poco::ClassLoader::instance() failed for non-singleton class."); msg.Message(Poco::format(" (%s \"%s\")", std::string(exc.name()), pluginName)); } } int main(int /*argc*/, char** /*argv*/) { PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION); ScopedLogMessage msg("ClassLoaderTest ", "start", "end"); std::string path(kSharedLibraryName); path.append(Poco::SharedLibrary::suffix()); Poco::ClassLoader<Plugin> cl; try { cl.loadLibrary(path); if(cl.isLibraryLoaded(path)) { msg.Message(Poco::format(" Size for manifest for \"%s\": %i", path, cl.manifestFor(path).size())); for(std::size_t i=0; i<kNumPlugin; ++i) { TestClassLoader(msg, cl, kPluginNames[i]); } cl.unloadLibrary(path); } } catch(Poco::LibraryLoadException& exc) { msg.Message(Poco::format(" %s \"%s\"", std::string(exc.name()), path)); } return 0; } |
Results of execution
・Linux/Mac 等では、libPlugin をインストールするために make install してから ClassLoaderTest
を実行する。
– On Linux
[0] ClassLoaderTest start Plugin initializing [0] Size for manifest for "libPlugin.so": 3 [0] PluginA created. [0] Poco::ClassLoader::instance() failed for non-singleton class. [0] (Invalid access "PluginA") [0] PluginB created. [0] Poco::ClassLoader::instance() failed for non-singleton class. [0] (Invalid access "PluginB") [0] PluginC instanciated. Plugin uninitialzing [0] ClassLoaderTest end |
– On Macintosh OSX 10.6.4
[0] ClassLoaderTest start Plugin initializing [0] Size for manifest for "libPlugin.dylib": 3 [0] PluginA created. [0] Poco::ClassLoader::instance() failed for non-singleton class. [0] (Invalid access "PluginA") [0] PluginB created. [0] Poco::ClassLoader::instance() failed for non-singleton class. [0] (Invalid access "PluginB") [0] PluginC instanciated. Plugin uninitialzing [0] ClassLoaderTest end |
– On Windows XP sp3
[0] ClassLoaderTest start Plugin initializing [0] Size for manifest for "libPlugin.dll": 3 [0] PluginA created. [0] Poco::ClassLoader::instance() failed for non-singleton class. [0] (Invalid access "PluginA") [0] PluginB created. [0] Poco::ClassLoader::instance() failed for non-singleton class. [0] (Invalid access "PluginB") [0] PluginC instanciated. Plugin uninitialzing [0] ClassLoaderTest end |
Downloads
・ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
(2013.05.31 updated)
・2010年7月27日からのダウンロード数:1137
Subversion
・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。
Reference
・http://pocoproject.org にある Shared Libraries のプレセンテーション。(PDF)
![]() |
Copyright © 2010 Round Square Inc. All rights reserved. |
---|
0 Comments.