Portable Guard Classes
Guarding other classes follows the same pattern. Assuming that all guards follow the pattern GuardXXX, where XXX is the name of a DB Interface Module class, you can use a simple macro to provide a portable interface, whether or not the compiler uses templates. The macro would look something like this:
#if compiler does not support templates
#define GUARD(Class, OBJECT) Guard ## Class guard__((OBJECT))
#else
#define GUARD(Class, OBJECT) Guard<Class> guard__((OBJECT))
#endif
The first macro concatenates the word
Guard with the name of the class,
RWDBConnection, and creates an instance of that class called
guard__, initialized with the
OBJECT (conn). The second macro simply instantiates an instance of class Guard with the type
Class (
Class = RWDBConnection). Even if your compiler or application does not support templates, you can use these macros in a portable manner as follows:
void doSomething(const RWDBConnection& conn)
{
// we’re going to use the connection so we’d better
// control access
GUARD(RWDBConnection, conn); // RWDBConnection supports the
// necessary interface.
// Do something on the connection.
// The mutex is released when the Guard instance goes out of
// scope.
}
Even when using the portable guard class template, you must still create a specialized guard class for each DB Interface Module object type you want to guard. For example, to guard an
RWDBSchema, you have to create:
class GuardRWDBSchema {
.
.
.
}
This is necessary in addition to using GUARD(RWDBSchema, mySchema) in your code.