使用句柄类封装继承体系

在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()的调用。







 

原文地址:https://www.cnblogs.com/wxxweb/p/2210755.html