zoukankan      html  css  js  c++  java
  • 使用句柄类封装继承体系

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







     

  • 相关阅读:
    国外可用的谷歌地图(可根据地址搜索经纬度)
    后台css框架(自用)
    DBHelp类sql分页(自用笔记)
    定制C++高效安全的运行时动态类型转换
    C++11右值引用和std::move语句实例解析
    浏览器内核-Webkit
    获取股票历史数据和当前数据的API
    从浏览器启动应用程序
    一个实时获取股票数据的安卓应用程序
    C++数据类型总结
  • 原文地址:https://www.cnblogs.com/wxxweb/p/2210755.html
Copyright © 2011-2022 走看看