在DLL封装的时候,一般都会采用接口类(Interface Class),即纯虚类,达到接口与实现分离的目的。但采用接口类,只能通过返回指针或引用来间接使用被封装的类。相对于这一点,采用句柄类(Handle Class)是个不错的替代方案。句柄类除了名称外,在使用方式上基本同被封装的类无差别。句柄类易用性是建立在耗费一定运行效率的基础之上的(当然,接口类也会消耗一定的运行效率),因此它一般用在运行效率要求不是很高的场合。另外,由于句柄类的编码量比接口类多,所以一般用来封装改动比较小的类。在适当的场景下,使用句柄类是种不错的选择,并且它也能用来封装继承体系,下面是使用句柄类封装继承体系的例子。
有一个继承体系,父类为 CBase,子类为 CDerived。它们对应的句柄类分别为HBase和HDerived,HBase和HDerived同样也是继承关系,如下:
#ifndef __CLASS_BASE_H__
#define __CLASS_BASE_H__
class CBase
{
public:
CBase(void);
virtual ~CBase(void);
public:
int GetData(void);
virtual void SetData(int nData);
private:
int m_nData;
};
#endif
#ifndef __CLASS_DERIVED_H__
#define __CLASS_DERIVED_H__
#include "Base.h"
class CDerived : public CBase
{
public:
CDerived(void);
virtual ~CDerived(void);
public:
virtual void SetData(int nData);
virtual void SetString(const char* pszString);
};
#endif
在HBase中使用智能指针std::auto_ptr对CBase对象指针进行管理。这里先暂时禁止句柄对象的拷贝和赋值,如果需要,可以使用带计数功能的智能指针进行管理,当最后一个句柄对象被析构时才释放掉CBase对象。
#ifndef __HANDLE_BASE_H__
#define __HANDLE_BASE_H__
#include <memory>
class CBase;
class HBase
{
public:
HBase(void);
virtual ~HBase(void);
protected:
HBase(CBase* pBase);
CBase* GetImpl(void);
private:
HBase(HBase& rhs);
HBase& operator =(HBase& rhs);
public:
int GetData(void);
virtual void SetData(int nData);
private:
std::auto_ptr<CBase> m_apImpl;
};
#endif
HBase的构造函数如下:
HBase::HBase(void)
: m_apImpl(new CBase)
{
}
HBase::HBase(CBase* pBase)
: m_apImpl(pBase)
{
}
其中默认构造函数用于在没有子类的情况下使用,带CBase对象指针参数的对象用于子类构造时调用。而GetImpl函数则提供给子类来获取CBase对象指针。
CBase* HBase::GetImpl(void)
{
return m_apImpl.get();
}
接下来看下HDerived:
#ifndef __HANDLE_DERIVED_H__
#define __HANDLE_DERIVED_H__
#include <memory>
#include "HBase.h"
class CDerived;
class HDerived : public HBase
{
public:
HDerived(void);
virtual ~HDerived(void);
private:
HDerived(HDerived& rhs);
HDerived& operator =(HDerived& rhs);
public:
virtual void SetData(int nData);
private:
CDerived* const m_pImpl; // 除构造函数以外不能被赋值
};
#endif
其中m_pImpl使用const修饰,使得它在构造时持有CDerived对象的指针,但之后不能再被赋值,避免无意改动。CDerived对象的指针先传递给HBase::m_apImpl管理,m_pImpl只是单纯地持有。
HDerived::HDerived(void)
: HBase(new CDerived)
, m_pImpl(static_cast<CDerived*>(HBase::GetImpl()))
{
}
这样当子类句柄析构时,只有到了父类层面才会析构掉CDerived对象指针。
HBase对CBase的封装的实现:
int HBase::GetData(void)
{
return m_apImpl->GetData();
}
void HBase::SetData(int nData)
{
m_apImpl->SetData(nData);
}
这样就能实现成员函数调用的多态性,但目前有个缺陷,就是不能实现像objDerived.CBase::SetData()的调用。