为什么要有接口?

接口就是一个程序与其它程序交流的窗口。就比如有一个电视机,我并不需要知道它是怎样工作的,我只要知道按电源键就可以开启电视,按节目加(+)减(-)可以切换电视频道就可以了。

Java程序员都知道Java中有interface可以实现对外的接口,但C++并没有接口这样的语法,那它要好怎样实现对外提供接口呢?我们可以通过纯虚函数定义一个抽象类,专门用来声明一个类的功能。

我们完成了一个程序模块的开发,要把这个程序模块给别人用,你肯定不会把源代码给他(那别人就完全撑屋你的技术了),你会把这个程序模块编译成一个库(静态库lib或动态库dll)再给别人用。那别人拿到你的库后怎样用呢?这就需要看你的程序所提供的接口。C++的封装性是特别好的(个人觉得比Java好多了,Java打成的jar包很容易就可以被反编译,C++要反编译就困难多了),我只要给你编译出的库和接口的头文件就可以了。



从一个实例讲讲实现方案

需要

我们先来看一个场景。假设有一个电子文档(Document)、一个文档下有多个页(Page),每个页下有多个文本单元(TextUnit,表示文档内元素的基本单位),一个文档中的所有文本单元对象都有唯一的ID。其类图关系如下:

 
图1 :类的关系图


设计

根据需求,我们可以定义三个类Document、Page、TextUnit分别表示文档、页、文本单元,每个类我们还需要一个对外的接口,于是需要三个对外的接口类IDocument、IPage、ITextUnit。 
根据这些类我们先创建.cpp文件和.h文件,组织一下工程(EBook)目录结构如下: 
 
图2: 工程目录结构

这里Document、Page、TextUnit就是具体的实现类,IDocument、IPage、ITextUnit就是对外提供的接口,这样就实现了实现与接口分离。


代码实现

IDocument.h:

#pragma once

class IPage;

class IDocument
{
public:
virtual ~IDocument(void){} public: //---------------------------------------------------------------
//function:
// GenerateId 生成本文档内唯一的文本对象ID
//Access:
// virtual public
//Parameter:
//Returns:
// int - 返回ID
//Remarks:
// ...
//author: luoweifu
//---------------------------------------------------------------
virtual int GenerateId() = 0; //---------------------------------------------------------------
//function:
// AddPage 添加一页
//Access:
// virtual public
//Parameter:
//Returns:
// IPage* - 返回页对象
//Remarks:
// ...
//author: luoweifu
//---------------------------------------------------------------
virtual IPage* AddPage() = 0;
};
 

IPage.h:

#pragma once

class ITextUnit;

class IPage
{
public:
virtual ~IPage(void){} public: //---------------------------------------------------------------
//function:
// AddTextUnit 添加一个文本单元
//Access:
// virtual public
//Parameter:
//Returns:
// ITextUnit* - 文本单元对象
//Remarks:
// ...
//author: luoweifu
//---------------------------------------------------------------
virtual ITextUnit* AddTextUnit() = 0;
};

ITextUnit.h

#pragma once

class ITextUnit
{
public:
~ITextUnit(void){} public:
//---------------------------------------------------------------
//function:
// GetId 获得ID
//Access:
// virtual public
//Parameter:
//Returns:
// int - 返回ID
//Remarks:
// ...
//author: luoweifu
//---------------------------------------------------------------
virtual int GetId() = 0; //---------------------------------------------------------------
//function:
// SetId 设置ID
//Access:
// virtual public
//Parameter:
// [in] int id - 要设置的ID
//Returns:
// void -
//Remarks:
// ...
//author: luoweifu
//---------------------------------------------------------------
virtual void SetId(int id) = 0; };

提供C接口

从上面的代码我们可以看到IPage可以由IDocument创建,ITextUnit可以由IPage创建。那问题来了,IDocument由谁来创建呢?这时我们可以提供两个全局的函数CreateDoc和DestroyDoc用来创建和销毁IDocument的对象指针,这两个函数是全局函数(C类型的函数),我们需要为其提供C的导出接口(这很重要)。其接口定义如下:

#pragma once

#include "IDocument.h"
#include "IPage.h"
#include "ITextUnit.h" //===============================================================
//要导出静态库时,导出库的工程要加预编译宏STATIC_LIBRARY,使用库的工程什么也要加STATIC_LIBRARY宏
//要导出动态库时,导出库的工程要加预编译宏EXPORT,使用库的工程什么也不用加
//===============================================================
#ifdef EXPORT //导出库
#define _API_ __declspec(dllexport)
#else //导入库
#define _API_ __declspec(dllimport)
#endif //EXPORT #ifdef STATIC_LIBRARY //导出静态库
#define EBAPI int
#else //导出动态库
#define EBAPI extern "C" _API_ int
#endif //STATIC_LIBRARY //---------------------------------------------------------------
//function:
// CreateDoc 创建Document对象
//Access:
// public
//Parameter:
// [in] IDocument * & pDocument -
//Returns:
// EBAPI -
//Remarks:
// ...
//author: luowf[/luoweifu]
//---------------------------------------------------------------
EBAPI CreateDoc(IDocument*& pDocument); //---------------------------------------------------------------
//function:
// DestroyDoc 销毁一个Document对象
//Access:
// public
//Parameter:
// [in] IDocument * pDocument -
//Returns:
// EBAPI -
//Remarks:
// ...
//author: luowf[/luoweifu]
//---------------------------------------------------------------
EBAPI DestroyDoc(IDocument* pDocument);

使用库

我们可以将EBook编译成一个静态库,然后再创建一个新的工程使用它。EBook工程设置:

 
 
图3: 工程配置(说明:上图中红色框中的EXPORT_STATIC已重命名为STATIC_LIBRARY的)

创建一个新的工程UseEBook使用EBook库。UseEBook工程配制: 
Generation Properties\C++\Preprocess\Preprocess Definitions:STATIC_LIBRARY

Generation Properties\Linker\General\Addtional Library Directories:lib库所在路径

Generation Properties\Linker\Input\Addtional Dependencies:EBook.lib

测试代码:

#include "stdafx.h"

#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
IDocument* pDoc = NULL;
if(CreateDoc(pDoc) != 0)
{
return -1;
} IPage* pPage = pDoc->AddPage();
ITextUnit* pTextUnit = pPage->AddTextUnit();
std::cout << pTextUnit->GetId() << std::endl; DestroyDoc(pDoc); return 0;
}
 

C++“隐藏实现,开放接口”的实现方案的更多相关文章

  1. 开放接口/RESTful/Api服务的设计和安全方案

    总体思路 这个涉及到两个方面问题:一个是接口访问认证问题,主要解决谁可以使用接口(用户登录验证.来路验证)一个是数据数据传输安全,主要解决接口数据被监听(HTTPS安全传输.敏感内容加密.数字签名) ...

  2. 开放接口/RESTful/Api服务的设计和安全方案详解

    一.总体思路 这个涉及到两个方面问题:一个是接口访问认证问题,主要解决谁可以使用接口(用户登录验证.来路验证)一个是数据数据传输安全,主要解决接口数据被监听(HTTPS安全传输.敏感内容加密.数字签名 ...

  3. 【转】App开放接口api安全性—Token签名sign的设计与实现

    前言 在app开放接口api的设计中,避免不了的就是安全性问题,因为大多数接口涉及到用户的个人信息以及一些敏感的数据,所以对这些接口需要进行身份的认证,那么这就需要用户提供一些信息,比如用户名密码等, ...

  4. App开放接口api安全性的设计与实现

    前言 在app开放接口api的设计中,避免不了的就是安全性问题,因为大多数接口涉及到用户的个人信息以及一些敏感的数据,所以对这些接口需要进行身份的认证, 那么这就需要用户提供一些信息,比如用户名密码等 ...

  5. App开放接口api安全性—Token签名sign的设计与实现

    前言 在app开放接口api的设计中,避免不了的就是安全性问题,因为大多数接口涉及到用户的个人信息以及一些敏感的数据,所以对这些接口需要进行身份的认证,那么这就需要用户提供一些信息,比如用户名密码等, ...

  6. 一次开放接口从需求分析到发布sdk线上包

    新年开场篇,欢迎来点赞:本篇和大家分享的是使用webapi做得接口服务验证框架,需求来源是我打算把上篇提到的图片验证码做成一种服务提供给大家,尽管我在上篇已经把代码打包开源了,但是如果有一种快速对接成 ...

  7. App开放接口API安全性 — Token签名sign的设计与实现

    在app开放接口API的设计中,避免不了的就是安全性问题. 一.https协议 对于一些敏感的API接口,需要使用https协议. https是在http超文本传输协议加入SSL层,它在网络间通信是加 ...

  8. [JAVA]基于微信公众平台开放接口编写的sdk

    最近在研究微信公众平台提供的公众服务号,以及提供的开放接口. 写了一个相对来说比较简单的基于java的微信sdk,目前实现的功能没有覆盖所有接口. 有兴趣的话,大家可以在这个基础上进行改进和完善,这样 ...

  9. APP开放接口API安全性——Token令牌Sign签名的设计与实现

    在APP开放接口API的设计中,避免不了的就是安全性问题. 一.https协议 对于一些敏感的API接口,需要使用https协议.https是在http超文本传输协议加入SSL层,它在网络间通信是加密 ...

随机推荐

  1. 控件之ReleLayout属性

    Android:控件布局(相对布局)RelativeLayout RelativeLayout是相对布局控件:以控件之间相对位置或相对父容器位置进行排列. 相对布局常用属性: 子类控件相对子类控件:值 ...

  2. 去中心化存储的QoS是什么?

    我的前面一篇文章讲到如何做去中化存储,文其中提到了QoS (Quality of Service),那么QoS是什么?为什么QoS那么重要?下面将详细描述. 什么是QoS? 提到QoS,就要先了解Qo ...

  3. AndroidStudio快捷键使用记录

    输入logt+回车 自动增加Tag的定义. private static final String TAG = "MainActivity"; 输入logd+回车 自动增加d级别的 ...

  4. js时间加减

    1.选择上一周方法(不算当天) $("#weekSel").click(function () { //当前时间 var now = new Date(); //当前时间往前推一周 ...

  5. 2018年1月 attribute VS prop 动画渲染

    attribute和prop和UI存在单向/双向绑定关系,参考 https://m.aliyun.com/yunqi/articles/31499 渲染流程 重绘和重排 ? requestAnimat ...

  6. 第二章:安装zabbix过程

    2.2 安装zabbix过程 2.2.1 安装方式选择 编译安装 (服务较多,环境复杂) yum安装(干净环境) 使用yum 需要镜像yum源 http://www.cnblogs.com/clsn/ ...

  7. 关于text-align和text-align-last

    很多人都用过text-align,基本上也比较熟悉这个属性. text-align: left; // 左对齐 text-align: right; // 右对齐 text-align: center ...

  8. 【Linux】使用ZStack私有云创建本地Linux服务器

    1.运维配置了一台Linux的主机,然后安装了ZStack,前面这部分操作运维处理了. 2.首先打开Zstack的网址地址,一般是一个IP地址(此时不写) 3.然后进入页面后,默认进入首页,此时可以按 ...

  9. django-BaseCommand自带的权限分组

    note:  应该是这样的结构,并且commands名字是固定的. 执行: python manage.py  initgroup initgroup.py # -*- coding: utf-8 - ...

  10. 学习excel的使用技巧一空格替换为0

    问题1  把excel表格中的空格  填充为0 方法1 选中CDE列    CRTL+F 查找空 替换为0 方法2 选中CDE列 CRTL+G 打开定位  点击条件定位  选择空值 点击确定  然后在 ...