一种最简单的实现
GPImpl.h/.cpp
class GPImpl { public: void DoSomeThing(); }; //------------------------------ void GPImpl::DoSomeThing() { cout << "DoSomeThing" << endl; }
GPExp.h/.cpp
#include "GPImpl.h" class GP_EXPORT IGPExp { public: void DoSomeThing(); private: GPImpl m_GPImpl; }; //---------------------------------- void IGPExp::DoSomeThing() { m_GPImpl.DoSomeThing(); }
这时如果我们提供了GPExp.h,那么m_GPImpl也暴露了,这时我们必须同时提供GPImpl.h,如果GPExp.h中有很多m_GPImpl这样的成员变量,那我们就得提供很多头文件了,而且只要其中任一个类有变动,我们都要给用户更新头文件,
也就是需要重新编译,对于大项目来说,这是要命的
//--------------------------------------------------------改进:
接口与实现分离
对IGPExp这个导出类写一个实现类GPExpImpl来实现它的所有功能,重点:GPExpImpl必须和IGPExp有相同的公有成员函数,因为它们一个是接口,一个是实现,要一一对应
GPImpl.h/.cpp
class GPImpl { public: void DoSomeThing(); }; /// <summary> /// GPExp的实现类 /// </summary> class GPExpImpl { public: void DoSomeThing(); private: GPImpl m_GPImpl; }; //---------------------------------------------------- void GPImpl::DoSomeThing() { cout << "DoSomeThing" << endl; } //==== void GPExpImpl::DoSomeThing() { m_GPImpl.DoSomeThing(); }
GPExp.h/.cpp
#pragma once class GPExpImpl;// 这样声明就不需要包含头文件 class GP_EXPORT IGPExp { public: IGPExp(); ~IGPExp(); void DoSomeThing(); private: GPExpImpl* m_pImpl; }; //---------------------------------------------------------- #include "GPExp.h" #include "inc\GPImpl.h" IGPExp::IGPExp() { m_pImpl = new GPExpImpl; } IGPExp::~IGPExp() { if (m_pImpl) { delete m_pImpl; } } void IGPExp::DoSomeThing() { m_pImpl->DoSomeThing(); }
划重点:前置声明class GPExpImpl;不需要包含头文件,但GPExpImpl只能使用指针,否则过不了编译
//-----------------------------------------深入,如果IGPExp有父类,父类有函数IsOk来控制是否调用DoSomeThing()
第一种方式:IGPExp::DoSomeThing()判断
GPExp.h/.cpp
class GPExpImpl; class GP_EXPORT IGPExpBase { public: bool IsOk(); virtual void DoSomeThing() = 0; }; class GP_EXPORT IGPExp : public IGPExpBase { public: IGPExp(); ~IGPExp(); void DoSomeThing(); private: GPExpImpl* m_pImpl; }; //---------------------------------------------------- #include "GPExp.h" #include "inc\GPImpl.h" bool IGPExpBase::IsOk() { return true; } //------------------------------- IGPExp::IGPExp() { m_pImpl = new GPExpImpl; } IGPExp::~IGPExp() { if (m_pImpl) { delete m_pImpl; } } void IGPExp::DoSomeThing() { if (IsOk()) { m_pImpl->DoSomeThing(); } }
这样的话,接口就加入了实现细节,从而接口和实现没有彻底分离
更好的方式,把IGPExp的指针传给实现GPExpImpl
GPImpl.h/.cpp
#pragma once class IGPExp; class GPImpl { public: void DoSomeThing(); }; /// <summary> /// GPExp的实现类 /// </summary> class GPExpImpl { public: GPExpImpl(IGPExp* pExp); void DoSomeThing(); private: GPImpl m_GPImpl; IGPExp* m_pExp; }; //----------------------------------------- #include "GPImpl.h" #include "..\\GPExp.h" #include <iostream> using namespace std; void GPImpl::DoSomeThing() { cout << "DoSomeThing" << endl; } //==== GPExpImpl::GPExpImpl(IGPExp* pExp) { m_pExp = pExp; } void GPExpImpl::DoSomeThing() { if (m_pExp->IsOk()) { m_GPImpl.DoSomeThing(); } }
GPExp.h/.cpp
class GPExpImpl; class GP_EXPORT IGPExpBase { public: bool IsOk(); virtual void DoSomeThing() = 0; }; class GP_EXPORT IGPExp : public IGPExpBase { public: IGPExp(); ~IGPExp(); void DoSomeThing(); private: GPExpImpl* m_pImpl; }; //-------------------------------------------- #include "GPExp.h" #include "inc\GPImpl.h" bool IGPExpBase::IsOk() { return true; } //------------------------------- IGPExp::IGPExp() { m_pImpl = new GPExpImpl(this); } IGPExp::~IGPExp() { if (m_pImpl) { delete m_pImpl; } } void IGPExp::DoSomeThing() { m_pImpl->DoSomeThing(); }
为什么不让GPExpImpl直接继承IGPExpBase呢,因为GPExpImpl定位为IGPExp的执行体,和IGPExpBase实在没有什么关系
合智互联客户成功服务热线:400-1565-661
留言评论
暂无留言