com的核心体系结构来源于c++标准实现
c++的重用机制有一个严重的缺陷:要想试用该源对象就必须提供源代码,这样的话宝贵的技术会随之暴露。要解决这个问题在windows下可以使用DLL(dynamic link library 动态链接库),即将数据库对象的所有代码都打包成一个DLL,并提供一个或多个用于说明函数和结构的头文件。
动态链接库的使用原理:在编译链接可执行文件时,只需要链接引入库,DLL中的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载DLL,访问DLL中导出的函数,这种方式称为动态链接。
首先学会创建动态库:(vc下创建)
1.在vc下新建一个动态库文件
2.选择动态库文件,工程名
3.选择第三个,它会自动生成统一的.cpp和.h文件
4.这样我们的动态库文件就建立完毕了
打开以后就是这个样子
将使用的函数声明继续往类中添加
函数实现放在.cpp中
如果在编译时出现这样的错误时:
请按照下方操作:
这是关于预处理的问题。。。。了解详情请问度娘^_^
动态库编译成功的标志:当当当
要将对象的实现封装成DLL,必须实现成员函数的引出,而引出成员函数最简单的方法是__declspec(dllexport)例如:
__declspec(dllexport)用于任何函数包括类的成员函数
应用程序要使用动态链接库可采用隐式和显式两种方法
隐式链接:
1.客户需将使用.dll .lib .h 文件添加到该工程文件夹下
2.在该工程的Project->Setting->Link->Object/library modules中加入xxxx.lib
显式链接过于复杂不在赘述
---------------------------------------------------------------------------------------------------------------
前面所创建的一个简单例子在这里说明一下:
- 某库厂商开发一个算法,能在常时间内进行子串的查找工作。特点是其查找时间与目的串的长度无关。 该厂商创建了一个字符串类。为此,他生成了一个头文件和一个实现文件
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the FASTSTRING_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// FASTSTRING_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
#ifdef FASTSTRING_EXPORTS
#define FASTSTRING_API __declspec(dllexport)
#else
#define FASTSTRING_API __declspec(dllimport)
#endif
// This class is exported from the Faststring.dll
class FASTSTRING_API CFaststring {
char * m_psz;
public:
CFaststring(void);
// TODO: add your methods here.
CFaststring (const char*psz);
~CFaststring ();
int Length(void)const;
char* Find(const char*psz)const;
};
extern FASTSTRING_API int nFaststring;
FASTSTRING_API int fnFaststring(void);
// Faststring.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "Faststring.h"
#include
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// This is an example of an exported variable
FASTSTRING_API int nFaststring=0;
// This is an example of an exported function.
FASTSTRING_API int fnFaststring(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see Faststring.h for the class definition
CFaststring::CFaststring()
{
return;
}
CFaststring::CFaststring(const char* psz):m_psz(new char[strlen(psz)+1])
{strcpy(m_psz,psz);} //分配内存
CFaststring::~CFaststring(void)
{ delete []m_psz;} //释放内存
int CFaststring::Length(void) const{
return strlen(m_psz);} //计算长度
char* CFaststring::Find(const char*psz)const
{
return strstr(m_psz,psz);
} //查找子串
- 静态链接
- 许多类库的做法
- 编译时刻的链接
- 静态链接的缺点
- 代码重复:多个程序各有自己的代码,需要更多的内存
- 客户程序占据更多的外存空间
- 库代码更新需要重新编译所有的客户程序
- 动态链接
- 运行时刻的链接
- 动态链接形式
- 编译时刻通过引入库
- 运行时刻完全动态
---------------------------------------------------------------------------------------------------------------
- 改造FastString,令其Length()函数的复杂度为O(1)。
- 解决方法:需要添加一个私有成员来直接计数字符串长度
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the FASTSTRING2_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// FASTSTRING2_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
#ifdef FASTSTRING2_EXPORTS
#define FASTSTRING2_API __declspec(dllexport)
#else
#define FASTSTRING2_API __declspec(dllimport)
#endif
// This class is exported from the FastString2.dll
class FASTSTRING2_API CFastString2 {
public:
CFastString2(void);
// TODO: add your methods here.
int m_cch;//v2.0 为了支持这个新的算法, 必须增加一个成员变量,以存储字符串的长度. 在构造函数中被赋值, 以后,当客户查询长度时,直接返回,无需计算. 导致了头文件的更新.
char * m_psz;
CFastString2 (const char*psz);
~CFastString2 ();
int Length(void)const;
char* Find(const char*psz)const;
};
extern FASTSTRING2_API int nFastString2;
FASTSTRING2_API int fnFastString2(void);
//
// FastString2.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "FastString2.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// This is an example of an exported variable
FASTSTRING2_API int nFastString2=0;
// This is an example of an exported function.
FASTSTRING2_API int fnFastString2(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see FastString2.h for the class definition
CFastString2::CFastString2()
{
return;
}
CFastString2::CFastString2(const char* psz)
:m_cch(strlen(psz)), m_psz(new char[m_cch+1])
{strcpy(m_psz,psz);}//长度保存下来
CFastString2::~CFastString2(void)
{ delete []m_psz;}
int CFastString2::Length(void) const{
return m_cch;}// 直接返回, 无需计算, 提高了效率.
char* CFastString2::Find(const char*psz)const
{ return strstr(m_psz,psz);}// 查找子串
---------------------------------------------------------------------------------------------------------------
- 接口类只描述希望客户知道的底层数据面貌
- 接口类不应包含任何用于对象实现的数据成员,应只包含操作方法的声明。
- 实现类将包含具体的数据成员与操作方法的具体实现。
- 接口类的二进制布局不会随着实现类数据成员的添加或删除而改变
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the FASTSTRINGITF_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// FASTSTRINGITF_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
#ifdef FASTSTRINGITF_EXPORTS
#define FASTSTRINGITF_API __declspec(dllexport)
#else
#define FASTSTRINGITF_API __declspec(dllimport)
#endif
// This class is exported from the FastStringItf.dll
class FastString; // 声明实现类, 但是不需要包含实现类的头文件
class FASTSTRINGITF_API CFastStringItf {
public:
CFastStringItf(void);
// TODO: add your methods here.
FastString* m_pThis; //实现类的指针.
CFastStringItf(const char*psz);
~CFastStringItf();
int Length(void)const;
char* Find(const char*psz) const;
};
extern FASTSTRINGITF_API int nFastStringItf;
FASTSTRINGITF_API int fnFastStringItf(void);
class FastString{
char * m_psz; //保存原始的字符串
int m_cch;
public:
FastString(const char*psz); //构造函数
~FastString(void);
int Length(void)const; //返回该字符串的长度
char* Find(const char*psz)const; //查找指定的子串
};
//
#include "FastString.h"
#include "string.h"
FastString::FastString(const char* psz):m_cch(strlen(psz)),m_psz(new char[m_cch+1])
{strcpy(m_psz,psz);}//长度保存下来
FastString::~FastString(void)
{ delete []m_psz;}
int FastString::Length(void) const{
return m_cch;}// 直接返回, 无需计算, 提高了效率.
char* FastString::Find(const char*psz)const
{ return strstr(m_psz,psz);}// 查找子串
///
// FastStringItf.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "FastStringItf.h"
#include "FastString.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// This is an example of an exported variable
FASTSTRINGITF_API int nFastStringItf=0;
// This is an example of an exported function.
FASTSTRINGITF_API int fnFastStringItf(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see FastStringItf.h for the class definition
CFastStringItf::CFastStringItf()
{
return;
}
CFastStringItf::CFastStringItf(const char *psz):m_pThis(new FastString(psz))//构造函数里面生成了实现类的具体事例通过这个指针指向实现类
{}
//{assert(m_pThis!=0);}//判断实现类是否为空
CFastStringItf::~CFastStringItf(void){
delete m_pThis;}//析构函数最后调用
int CFastStringItf::Length(void) const{
return m_pThis->Length();}//传递到实现类的lengh
char* CFastStringItf::Find(const char*psz)const{
return m_pThis->Find(psz);}
采用句柄类把接口与实现相分离,使得用户与对象之间形成一道精密的协议,用户只有通过接口类才能实现与对象之间的通信,它不依赖于实现类的任何细节。
但这种方法也有缺点:接口类必须把每个方法调用显式的传递给实现类,简单的类接口少,复杂的就会很麻烦。所以这个方法并没有完全解决这个问题。
---------------------------------------------------------------------------------------------------------------
再回到这个例子上,通过抽象类创建的IFaststring类:
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the IFASTSTRING1_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// IFASTSTRING1_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
#ifdef IFASTSTRING1_EXPORTS
#define IFASTSTRING1_API __declspec(dllexport)
#else
#define IFASTSTRING1_API __declspec(dllimport)
#endif
// This class is exported from the IFastString1.dll
class IFASTSTRING1_API CIFastString1 {
public:
// CIFastString1(void);
// TODO: add your methods here.
virtual int Length(void) const=0;
virtual char* Find(const char*psz)const=0;
};
class FastString : public CIFastString1 //派生于接口类
{
const int m_cch;
char*m_psz;
public:
FastString(const char* psz);
~FastString();
int Length(void)const; //不需要加上virtual 关键字
char* Find(const char*psz)const;//覆盖了基类的虚函数
};
extern "C"{ __declspec(dllexport)
CIFastString1 *CreateFastString(const char*psz);}//导出函数为接口类的指针
extern IFASTSTRING1_API int nIFastString1;
IFASTSTRING1_API int fnIFastString1(void);
///
// IFastString1.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "IFastString1.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// This is an example of an exported variable
IFASTSTRING1_API int nIFastString1=0;
// This is an example of an exported function.
IFASTSTRING1_API int fnIFastString1(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see IFastString1.h for the class definition
// CIFastString1::CIFastString1()
// {
// return;
// }
CIFastString1 * 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);}
FastString::~FastString(void)
{ delete []m_psz;} // 释放成员变量占用的内存.
int FastString::Length(void) const{
return m_cch;}
char* FastString::Find(const char*psz)const
{
return strstr(m_psz,psz);
}
---------------------------------------------------------------------------------------------------------------
- 用一个基类指针pIFS指向一个子类对象。delete pIFS;将导致基类的析构函数被调用.而实现类(派生类)中所动态分配的保存字符串的内存将不能得到及时释放.造成内存泄漏问题
- 简单的解决方法1:
- 把基类的析构函数声明为虚的.这样,派生类的析构函数也是虚的.执行delete pIFS;时,由于pIFS指向的是派生类的对象,所以调用的是派生类的析构函数.可以完整地释放派生类对象所占用的存储空间。但是如果将接口类的析构函数做成虚的,会破坏接口类的编译器独立性。因为虚析构函数在虚表中的位置随着编译器的不同而不同。
- 解决方法2:
- 给接口类增加一个Delete方法,作为其另一个纯虚函数,在派生类中实现自身的删除,以导致正确的析构过程。
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the IFASTSTRINGD_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// IFASTSTRINGD_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
#ifdef IFASTSTRINGD_EXPORTS
#define IFASTSTRINGD_API __declspec(dllexport)
#else
#define IFASTSTRINGD_API __declspec(dllimport)
#endif
// This class is exported from the IFastStringD.dll
class IFASTSTRINGD_API CIFastStringD {
public:
//CIFastStringD(void);
// TODO: add your methods here.
virtual void Delete(void)=0;
virtual int Length(void) const=0;//没有实现的虚函数,典型的纯虚函数
virtual char* Find(const char*psz)const=0;
};
class FastString : public CIFastStringD //派生于接口类
{
// const int m_cch;
char*m_psz;
public:
FastString(const char* psz);
~FastString();
void Delete(void);
int Length(void)const; //不需要加上virtual 关键字
char* Find(const char*psz)const;//覆盖了基类的虚函数
};
extern "C"{ __declspec(dllexport)
CIFastStringD *CreateFastString(const char*psz);}//导出函数返回值为接口类的指针
extern IFASTSTRINGD_API int nIFastStringD;
IFASTSTRINGD_API int fnIFastStringD(void);
// IFastStringD.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "IFastStringD.h"
#include
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// This is an example of an exported variable
IFASTSTRINGD_API int nIFastStringD=0;
// This is an example of an exported function.
IFASTSTRINGD_API int fnIFastStringD(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see IFastStringD.h for the class definition
// CIFastStringD::CIFastStringD()
// {
// return;
// }
CIFastStringD * CreateFastString(const char * psz)
{return new FastString(psz);} //创建一个实现类的实例. 返回值是接口指针.
void FastString::Delete()
{ delete this; } //由用户调用,删除自身.
FastString::~FastString(void)
{ delete []m_psz;} // 由上一个函数引起,释放成员变量占用的内存.
//构造函数, Length Find 等不变,略.
/
// FastString::FastString(const int ch):m_cch(ch)
// {
// return;
// }
FastString::FastString(const char* psz):m_psz(new char[strlen(psz)+1])
{strcpy(m_psz,psz);} //分配内存
int FastString::Length(void) const{
return strlen(m_psz);} //计算长度
char* FastString::Find(const char*psz)const
{
return strstr(m_psz,psz);
} //查找子串
从C++过度到com需要经历的过程:
实现接口的引用计数
对象允许多个接口
类厂对象使用标准IClassFactory接口
使用_stdcall调用约定
实现DLL动态卸载
实现对象自注册
声明:文中所提及的源码都是在动态链接库下实现的,所以会有些看起来奇怪的宏注释之类的,还有命名可能会有些奇怪,我发现所有构建好的类动态库会自动在其前面加上一个C,例如CFaststring,如果你在VC下按照上面的步骤同样建立动态链接库的话,会看到这些代码是如何出来的。。。。本文章仅供参考,如发现问题欢迎留言骚扰( ̄▽ ̄)