在用C++写要导出类的库时,我们经常只想暴露接口,而隐藏类的实现细节。也就是说我们提供的头文件里只提供要暴露的公共成员函数的声明,类的其他所有信息都不会在这个头文件里面显示出来。这个时候就要用到接口与实现分离的技术。
下面用一个最简单的例子来说明。
类ClxExp是我们要导出的类,其中有一个私有成员变量是ClxTest类的对象,各个文件内容如下:
lxTest.h文件内容:
classClxTest
{
public:
ClxTest();
virtual~ClxTest();
voidDoSomething();
};
lxTest.cpp文件内容:
#include"lxTest.h"
#include<iostream>
usingnamespacestd;
ClxTest::ClxTest()
{
}
ClxTest::~ClxTest()
{
}
voidClxTest::DoSomething()
{
cout<<"DosomethinginclassClxTest!"<<endl;
}
lxExp.h文件内容:
#include"lxTest.h"
classClxExp
{
public:
ClxExp();
virtual~ClxExp();
voidDoSomething();
private:
ClxTestm_lxTest;
voidlxTest();
};
lxExp.cpp文件内容:
#include"lxExp.h"
ClxExp::ClxExp()
{
}
ClxExp::~ClxExp()
{
}
//其实该方法在这里并没有必要,我这样只是为了说明调用关系
voidClxExp::lxTest()
{
m_lxTest.DoSomething();
}
voidClxExp::DoSomething()
{
lxTest();
}
为了让用户能使用我们的类ClxExp,我们必须提供lxExp.h文件,这样类ClxExp的私有成员也暴露给用户了。而且,仅仅提供lxExp.h文件是不够的,因为lxExp.h文件include了lxTest.h文件,在这种情况下,我们还要提供lxTest.h文件。那样ClxExp类的实现细节就全暴露给用户了。另外,当我们对类ClxTest做了修改(如添加或删除一些成员变量或方法)时,我们还要给用户更新lxTest.h文件,而这个文件是跟接口无关的。如果类ClxExp里面有很多像m_lxTest那样的对象的话,我们就要给用户提供N个像lxTest.h那样的头文件,而且其中任何一个类有改动,我们都要给用户更新头文件。还有一点就是用户在这种情况下必须进行重新编译!上面是非常小的一个例子,重新编译的时间可以忽略不计。但是,如果类ClxExp被用户大量使用的话,那么在一个大项目中,重新编译的时候我们就有时间可以去喝杯咖啡什么的了。当然上面的种种情况不是我们想看到的!你也可以想像一下用户在自己程序不用改动的情况下要不停的更新头文件和编译时,他们心里会骂些什么。其实对用户来说,他们只关心类ClxExp的接口DoSomething()方法。那我们怎么才能只暴露类ClxExp的DoSomething()方法而不又产生上面所说的那些问题呢?答案就是--接口与实现的分离。我可以让类ClxExp定义接口,而把实现放在另外一个类里面。下面是具体的方法:
首先,添加一个实现类ClxImplement来实现ClxExp的所有功能。注意:类ClxImplement有着跟类ClxExp一样的公有成员函数,因为他们的接口要完全一致。
lxImplement.h文件内容:
#include"lxTest.h"
classClxImplement
{
public:
ClxImplement();
~ClxImplement();
voidDoSomething();
private:
ClxTestm_lxTest;
voidlxTest();
};
lxImplement.cpp文件内容:
#include"lxImplement.h"
ClxImplement::ClxImplement()
{
}
ClxImplement::~ClxImplement()
{
}
voidClxImplement::lxTest()
{
m_lxTest.DoSomething();
}
voidClxImplement::DoSomething()
{
lxTest();
}
然后,修改类ClxExp。
修改后的lxExp.h文件内容:
//前置声明
classClxImplement;
classClxExp
{
public:
ClxExp();
virtual~ClxExp();
voidDoSomething();
private:
//声明一个类ClxImplement的指针,不需要知道类ClxImplement的定义
ClxImplement*m_pImpl;
};
修改后的lxExp.cpp文件内容:
#include "lxExp.h"
//在这里包含类ClxImplement的定义头文件
#include"lxImplement.h"
ClxExp::ClxExp()
{
m_pImpl=newClxImplement;
}
ClxExp::~ClxExp()
{
if(m_pImpl)
deletem_pImpl;
}
voidClxExp::DoSomething()
{
m_pImpl->DoSomething();
}
通过上面的方法就实现了类ClxExp的接口与实现的分离。请注意两个文件中的注释。类ClxExp里面声明的只是接口而已,而真正的实现细节被隐藏到了类ClxImplement里面。为了能在类ClxExp中使用类ClxImplement而不include头文件lxImplement.h,就必须有前置声明class ClxImplement,而且只能使用指向类ClxImplement对象的指针,否则就不能通过编译。在发布库文件的时候,我们只需给用户提供一个头文件lxExp.h就行了,不会暴露类ClxExp的任何实现细节。而且我们对类ClxTest的任何改动,都不需要再给用户更新头文件(当然,库文件是要更新的,但是这种情况下用户也不用重新编译!)。这样做还有一个好处就是,可以在分析阶段由系统分析员或者高级程序员来先把类的接口定义好,甚至可以把接口代码写好(例如上面修改后的lxExp.h文件和lxExp.cpp文件),而把类的具体实现交给其他程序员开发。
分享到:
相关推荐
4.5.1 数据交换与传输协议的分离 4.5.2 数据格式和传输介质 4.5.2.1 FORMATETC结构 4.5.2.2 STGMEDIUM结构 4.5.3 数据对象和IDataObject接口 4.5.4 MFC对统一数据传输的支持 4.5.4.1 COleDataSource类 4.5.4.2 ...
4.3 数据输入输出的概念及在 C 语言中的实现 54 4.4 字符数据的输入输出 54 4.4.1 putchar 函数(字符输出函数) 54 4.4.2 getchar函数(键盘输入函数) 55 4.5 格式输入与输出 55 4.5.1 printf 函数(格式输出函数...
与之相反,gSOAP利用编译器技术提供了一组透明化的SOAP API,并将与开发无关的SOAP实现细节相关的内容对用户隐藏起来。 gSOAP的编译器能够自动的将用户定义的本地化的C或C++数据类型转变为符合XML语法的数据结构,...
18.4.6 使用散列和分离链实现ADT字典 544 第19章 平衡查找树 551 19.1 平衡查找树 552 19.2 2-3树 553 19.2.1 遍历2-3树 555 19.2.2 查找2-3树 556 19.2.3 在2-3树中插入数据 558 19.2.4 从2-3树中删除数据 ...
b) 接口与实现分离 对外提供接口文件,在插件内部用类来实现一个或多个接口,不需要对外导出该类或暴露实现细节。这样还有一个好处是只有约定了接口就可以让多个模块并行开发,模块相互之间不存在编译依赖(不需要...
3.2.1 C++类的定义与实现 3.2.2 构造函数与析构函数 3.2.3 静态成员 3.2.4 this指针 3.2.5 友元函数 3.3 类的继承机制 3.3.1 基类与派生类概念 3.3.2 单一派生 3.3.3 多重继承 3.3.4 虚基类 3.4 多态性与虚函数 3.5 ...
3.2.1 C++类的定义与实现 3.2.2 构造函数与析构函数 3.2.3 静态成员 3.2.4 this指针 3.2.5 友元函数 3.3 类的继承机制 3.3.1 基类与派生类概念 3.3.2 单一派生 3.3.3 多重继承 3.3.4 虚基类 3.4 多态性与虚函数 3.5 ...
4.3 数据输入输出的概念及在 C 语言中的实现 54 4.4 字符数据的输入输出 54 4.4.1 putchar 函数(字符输出函数) 54 4.4.2 getchar函数(键盘输入函数) 55 4.5 格式输入与输出 55 4.5.1 printf 函数(格式输出函数...
6. **集成能力**:MATLAB可以与其他编程语言(如C、C++、Java、Python等)及外部应用程序进行数据交换和联合开发,也可以调用硬件接口进行实时实验和控制。 7. **交互式工作空间**:用户可以在命令窗口中直接输入...
相对于cryptopp,SunJCE要容易上手得多,几乎不需要再做封装,不过为了跟C++封装统一,也做了简单的封装,保持C++接口和Java接口相近。 C++封装在Visual Studio 2003下测试通过,Java封装在jdk1.5.0_14下测试通过...
基于OpenCV图像识别技术实现快递信息的识别以及二维码的道路节点信息识别,9轴陀螺仪的姿态获取技术来作为底层小车的运动控制实现直走以及精确的转向,以及可能会使用ROS机器人系统实现多机器人协同工作。...
4、描述本系统的界面,通过分别定义成员的不同属性,为抽象和实现提供分离的接口。 四、设计工具 1、设计工具:建议使用.net 系列中的C++ 编译器,但不局限于此。 2、不提倡使用MFC和可视化开发技术。 五、设计报告...
对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同...
该项目都是测试过了的,真实可靠,请放心使用...Spring Boot 提供了 spring-boot-starter-websocket 来快速实现消息推送,同时也可以整合流行的 RPC 框架,提供 RPC 服务接口(只要简单加入对应的 starter 组件即可)。
实现上期技术的行情和交易接口,通过qt mvc 编程模型,实现前后台分离,前台获取用户输入参数,中间层辅助数据传输业务处理,后台专注行情数据分析,交易决策。参数设定后,界面自动退出,后台继续运行算法进行交易...
对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同...
项目特点:前后端分离,数据库接口设计,架构设计,功能开发,上线运维 【项目资源】: 包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发...