So, let us consider in detail the process of creating a dynamically loaded class using the library of PDL. First of all, should define an interface class, which we will work with a downloaded copy of the class. Mandatory condition: this interface must inherit from the class of PDL:: DynamicClass. Let us closely to the definition of care DynamicClass:
ID
сlass DynamicClass
{
public :
/**
* @brief Get class name
* return class name
*/
virtual const char * GetClassName() const throw () = 0;

/**
* @brief Destroy class instance
*/
void Destroy() throw () { delete this ; }
protected:
/ **
* @ Brief Destructor
* /
virtual ~ DynamicClass () throw () (;
);
Pure virtual function GetClassName () returns the name of the class. You do not need to worry about its definition, just below I will explain why.
Non-virtual function Destroy () is used to destroy the instance of class. This is a protected destructor to prevent its direct challenge. Why exactly this is done, will be explained below.
Thus, our interface, we must inherit from the PDL:: DynamicClass and defining the virtual destructor, preferably in a section protected (so as not to disrupt the ideology of PDL).
In addition, the ad interface is necessary to write a macro DECLARE_DYNAMIC_CLASS, referring to it as a parameter the name of the class. If you look at the description of the macro, it is clear its purpose: it simply defines a virtual function GetClassName ():
ID
#define DECLARE_DYNAMIC_CLASS( className ) \
public : \
virtual const char * GetClassName() const throw () { return #className; }
And finally, we add to the description of the interface ad pure virtual methods that implement the functionality of future useful dynamically loaded classes. Suppose that in our case, this method will void DoSomething ().

As a result, we have the following interface declaration:
ID
#include <DynamicClass.hpp>
slass MyTestInterface: public PDL:: DynamicClass
(
public:
/ **
* @ Brief Test method
* /
virtual void DoSomething () throw () = 0;
/ **
* @ Brief Declare this class dynamically loadable
* /
DECLARE_DYNAMIC_CLASS (MyTestInterface)
);
This ad should be placed in a separate header file, in our case - MyTestInterface.hpp, so as to ensure compatibility, it will be included when building a dynamically loaded class, and with his immediate download and use.
Then the class should identify himself, having inherited it from an abstract interface MyTestInterface and methods for identifying, implementing useful functionality. Furthermore, the class must be exported using macro EXPORT_DYNAMIC_CLASS. Please note that this macro should be outside the definition of class:
ID
#include <MyTestInterface.hpp>
#include <stdio.h>
class MyTestClass1: public MyTestInterface
(
public:
/ **
* @ Brief Test method
* /
void DoSomething () throw ()
(
fprintf (stderr, "MyTestClass1:: DoSomething () \ n");
)
);
EXPORT_DYNAMIC_CLASS (MyTestClass1)
A glance at the definition of a macro EXPORT_DYNAMIC_CLASS (file DynamicClass.hpp):
ID
#define EXPORT_DYNAMIC_CLASS( className ) \
extern "C" PDL_DECL_EXPORT PDL:ynamicClass * Create##className() \
{ \
try { return new className(); } \
catch ( ... ) {;; } \
return NULL; \
}
This macro declares and defines the exported functions Create <imya_klassa>, which creates and returns a copy of that in the parameter class. The modifier extern "C" is needed to ensure that the compiler does not decorate the name of the function in the library. Macro PDL_DECL_EXPORT declare the exported function. It is defined in the file platform.h and its implementation depends on a specific platform.

Attention is drawn to two things. First, the export function lovyatsya all exclusions constructor. If the constructor call crash ejection exceptions, the function simply returns NULL. This is due to the difficulties encountered when trying to handle an exception in the body of the emitted code plug. Secondly, the exported function returns a pointer to the PDL:: DynamicClass, which implicitly transforms the created object classes. Thus, if we forget to inherit an interface created by the class of PDL:: DynamicClass, the compiler will remind us of this.

Once the class is created, we can compile the plugin. It should be noted that a plugin can contain several different dynamically loaded classes, the most important condition: they must be unique within the plugin names. It should be remembered that export using a macro EXPORT_DYNAMIC_CLASS need each of the classes.

The use of dynamically loaded classes
So, we have a library-plugin containing the dynamically loadable class. Now we will try to use this class.
To begin, we need to instance the dynamic loader classes - PDL:: DynamicLoader. This class is a Singleton, that is there is always a single copy. For references to this instance using the static method DynamicLoader:: Instance ():
ID
PDL:ynamicLoader & dynamicLoader = PDL:ynamicLoader::Instance();
Next, we need to load the instance of the class and get a pointer to it:
ID
MyTestInterface * instance =
dynamicLoader.GetClassInstance< MyTestInterface >( myLibName, "MyTestClass1" );
Here myLibName - this is the name of the library, a plug-in, for example, "MyTestClass1.dll" or "MyTestClass.so". Do not forget to add a header file defining the interface of class - in this case , mentioned above.
Finally, call the method of the class is loaded:
ID
instance -> DoSomething();
Because the dynamic loader in case of error throws exception of type PDL:: LoaderException, will be properly wrap his calls in the block try / catch. Full example code would look like this:
ID
#include <MyTestInterface.hpp>
#include <stdio.h>
try
(
PDL:: DynamicLoader & dynamicLoader = PDL:: DynamicLoader:: Instance ();
MyTestInterface * instance =
dynamicLoader.GetClassInstance <MyTestInterface> (myLibName, "MyTestClass1");
instance -> DoSomething ();
)
catch (PDL:: LoaderException & ex)
(
fprintf (stderr, "Loader exception:% s \ n", ex.what ());
)

It is worth noting another interesting point: all the dynamically loaded classes behave like Singleton. In other words, call DynamicLoader:: GetInstance () with the same name and library of the same name the class will be returned a pointer to the already loaded instance. This is done to help control the removal of instances dynamically loaded classes. If you need to create multiple instances of classes, it is recommended to implement the factory class and make it dynamically loaded.
But what about deleted instances of classes loaded? To do this, and there is a method DynamicClass:: Destroy (). Invoke directly it does not need to - this makes the boot itself, in its destructor, or when calling the method DynamicLoader:: Reset (). Why is not caused by normal destructor? The point is that some of the subtleties of dynamic memory allocation mechanism is different from compiler to compiler. Imagine that the plugin is compiled compiler A, and the main program that uses it - the compiler B. If we load a class from a plugin, its instance is created with code generated compiler A. And if we try to delete this instance of the code, the main program simply by calling a destructor, then it will attempt to remove the code generated by compilers B. There may be case.

To avoid such problems, destructor ~ DynamicClass () is made secure, but instead should call the method DynamicClass:: Destroy (). This method will guarantee that the destructor of class code is compiled by the same compiler that the code of its designer.

Spoon tar
There is one subtle point associated with the names of the libraries. If the library is changing, it is believed that this is a completely different library, though differently written names may point to the same library. For example: C: \ MyProg \ libs \ mylib.dll and MyLIB.DLL.

It should also be noted that the library PDL does not solve the problem with different methods of decoration names different compilers - the task at the moment is not.

Currently, the library tested on the following platforms:
FreeBSD 6.2
Debian 4.0 Linux 2.6.18-4
openSUSE 10.2
Windows XP
I will be grateful for any information regarding the work of PDL on other platforms.