DLL导出函数Interface与实现分离
时间:2022-07-23
本文章向大家介绍DLL导出函数Interface与实现分离,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一种最简单的实现
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 "incGPImpl.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 "incGPImpl.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 "incGPImpl.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实在没有什么关系
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 集智智能课程表项目 实战指南
- ZeroLogon(CVE-2020-1472) 分析与狩猎
- 什么是数字资产?
- 我要偷偷的学Python,然后惊呆所有人(第一天)
- Python 中的上下文管理
- 我是如何阅读JDK源码的?
- Docker以root身份登录到容器
- SOAPUI访问WEBSERVICE案例
- 编译安装nginx
- 磁盘高可用解决方案(DBA).md
- Python 3.7 + HttpRunner 初探
- 数据库PostrageSQL-服务器配置(复制)
- 高可用服务解决方案(DBA).md
- dotnet 使用 Interlocked 实现一个无锁的快速无序仅写集合
- 利用Python将gff3转换成gtf格式