使用句柄类封装继承体系

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







 

 

 

posted @   Atypiape  阅读(908)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示