Abstract Classes for Interface
We need to find a factor in compilers that we rely across the vendors. This means to find a factor which will not impact which compiler is used to compile client or the DLL. The most suited feature across the board was found to be Virtual Table and Virtual Pointers. This mechanism remained constant.
We need to have a pure virtual interface class for our FastString class.Which would be then implemented by the FastString Class.
/////////////////////////////////// ifaststring.h /////////////////////////////////////////////////////
class IFastString {
public:
virtual int Length(void) canst = 0;
virtual int Find(const char *psz) canst = 0;
} ;
/////////////////////////////////// FastString.cpp ////////////////////////////////////////////////
class FastString : public IFastString {
canst int m_cch; // count of characters
char *m_psz;
public:
FastString(const char *psz);
-FastString(void);
int Length(void) canst; II returns # of characters
int Find(const char *psz) canst; II returns offset
} ;
The FastString derives from IFastString so gets a copy of the vptr but the compiler now fills it with the pointer to the implementation of the Length and Find functions.
We have a problem here because even if the client cannot instantiate the object of the DLL without having knowledge of the class implementation of the FastString. The most common solution is to provide provide global function that would call new function for the client. [ Note that global extern function is consistent across the compilers so this will not be an issue ].
Another obstacle is to delete the object which has been created.
IFastString *pfs = CreateFastString("Deface me");
int n = pfs->Find("ace me");
delete pfs;
The destructor of the interface class is not virtual, which would mean by default the object would not delete objects derived from it. For this case FastString object will not be deleted when the IFastString is deleted. Obvious solution would be to make the destructor virtual, but this is again compiler dependent and which position in the virtual table the destructor is placed is unknown.
Solution to this is to write a Delete function for the FastString object.
// ifaststring.h ///////////
class IFastString {
public:
virtual void Delete(void) = 0;
virtual int Length(void) const = 0;
virtual int Find(const char *psz) const 0;
} ;
extern "C"
IFastString *CreateFastString (const char *psz);
// faststring.h ///////////////////////////////////
#include "ifaststring.h"
class FastString : public IFastString {
const int m_cch; // count of characters
char ''''m_psz;
public:
FastString(const char *psz);
~FastString(void);
void Delete(void); // deletes this instance
int Length(void) const; // returns # of characters
int Find(const char *psz) const; // returns offset
} ;
// faststring.cpp ///////////////////////////////////
#include <string.h>
#include "faststring.h"
IFastString* CreateFastString (const char *psz) {
return new FastString(psz);
}
FastString::FastString(const char *psz)
m_cch(strlen(psz)), m_psz(new char[m_cch + 1]) {
strcpy(m_psz, psz);
}
void FastString::Delete(void) {
delete this;
}
FastString::-FastString(void) {
delete[] m_psz;
}
int FastString::Length(void) const {
return m_cch;
}
int FastString::Find(const char *psz) canst {
// 0(1) lookup code deleted for clarity
}
Runtime Polymorphism
It is possible to create desired objects which inherit from the same interface and use them manipulatively. Now lets consider this situation where the vendors to give two versions of Faststring and provide client the option to load them on demand.
Note: The LoadLibrary function is preferred to directly calling NEW , because it will work on clients which have very thin infrastructure. For example if the object implementation is not installed. MAPI uses LoadLibrary to load DLLs on a minimally configured machines.
The polymorphism can be implemented as in the following example , where vendor is providing capability of reverse search with the DLL in addition to regular function.
IFastString *
CallCreateFastString(const char *psz,bool bLeftToRight = true) {
static IFastString * (*pfnlr)(const char *) = 0;
static IFastString * (*pfnrl)(const char *) = 0;
IFastString *(**ppfn)(const char *) = &pfnlr;
const TCHAR *pszDll = _TEXT("FastString.DLL");
if (!bLeftToRight) {
pszDll = _TEXT("FastStringRL.DLL");
ppfn = &pfnrl;
}
if (!(*ppfn)) { // init ptr 1st time through
const char szFn[] = "CreateFastString";
HINSTANCE h = LoadLibrary(pszDll);
if (h)
*(FARPROC*)ppfn = GetProcAddress(h, szFn);
}
return (*ppfn) ? (*ppfn)(psz) : 0;
}
The client implementation for both the case would be like
pfs = CallCreateFastString("Hi Bob!"); //Will Load FastString.DLL
n = pfs->Find("ob");
pfs = CallCreateFastString("Hi Bob!", false);//Will Load FastStringRL.DLL
n = pfs->Find("ob");
No comments:
Post a Comment