一种最简单的实现
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实在没有什么关系