为什么要有接口?

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

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. Socket传输简单的信息以及粘包问题的解决

    一.简单的socket程序——传输简短文字: # -*- coding: utf-8 -*- # -*- Author: WangHW -*- import socket whw_client = s ...

  2. [UE4]嵌套Canvas

  3. 0000 - Spring 中常用注解原理剖析

    1.概述 Spring 框架核心组件之一是 IOC,IOC 则管理 Bean 的创建和 Bean 之间的依赖注入,对于 Bean 的创建可以通过在 XML 里面使用 <bean/> 标签来 ...

  4. GAC 注册查看与删除

    1.复制以下命令粘贴到以管理员权限运行的命令行程序里,回车运行(前提条件得有gacutil.exe注册工具): cd "C:\NETFX 4.0 Tools" 以windows7 ...

  5. php数组和部分操作函数

    1. 数组定义 数组的定义使用 array()方式定义,可以定义空数组: <?php $number = array(1,3,5,7,9); //定义空数组 $result = array(); ...

  6. Spring之jdbcTemplate:查询的三种方式(单个值、单个对象、对象集合)

    JdbcTemplateDemo2.java package helloworld.jdbcTemplate; import org.springframework.jdbc.core.JdbcTem ...

  7. linux运行.sh命令

    # chmod +x AAA.sh  授权 # ./AAA.sh                  运行  

  8. 安全测试3_Web后端知识学习

    其实中间还应该学习下web服务和数据库的基础,对于web服务大家可以回家玩下tomcat或者wamp等东西,数据库的话大家掌握基本的增删该查就好了,另外最好掌握下数据库的内置函数,如:concat() ...

  9. Ruby学习笔记5: 动态web app的建立 (2)

    上一节里,我们搭建了一个数据库的结构,并用index验证了request-response cycle,如下图: 1. Add show method into Controller 这一节,我们要继 ...

  10. uva-321-暴力枚举-隐式图搜索

    题意:给你n个房间,有许多灯的控制开关,i房间灯的开关在j房间,未开灯的房间不能进,i房间和j房间之间如果没有门,也不能从i进入到j,开始房间是1,并且灯是开着的,问你是否能够走到最后一个房间n,并且 ...