C++ API功能设计的实现

 更新时间:2022年08月30日 08:46:45   作者:Colin-YYYY  
C++ API中看似很小的修改,都可能会影响到生成的对象和库文件的二进制表示,如果客户想替换共享库使之工作,就不能简单的替换库文件了事,而往往需要重新编译

前言

创建类来表示API中的每个关键对象,同时提供这些类的方法

此处的API风格指的是如何表现API的功能,以下4种:

  • C API

可以用C编译器编译的API。这种API只包含一组自由函数以及辅助的数据结构和常量。这种风格的接口不包含对象或继承,因此被称为纯C模式

  • 面向对象的C++ API

这种风格涉及对象(其中包含相关的数据与方法)的使用以及继承、封装和多态等概念的应用

  • 基于模板的API

通过模板功能,C++也支持泛型编程和元编程。它支持以泛型类型的方式编写函数和数据结构,在以后使用时,泛型类型可以通过具体类型来实例化,从而实现特化

  • 数据驱动型API

这类接口的特点是,将参数通过灵活的数据结构打包,连同命名的命令一起发送给处理程序,而不是调用特定的方法和自由函数

纯C API

C语言不支持对象封装和继承层次结构等概念,因此,纯C语法的API必须使用一组更为受限的语言特性来表示,比如typedef、结构体和全局命名空间中的函数调用等。因为C语言中没有namespace关键字,要避免与其他C库中的名字发生冲突,对这种风格的API而言,所有公开的函数和数据结构应该使用一个公共的前缀

当然,也可以使用内部链接隐藏实现中的符号名,比如将符号名声明为静态的,这样它们的作用域就限制在.c文件之中了。通过这种方式,可以确保任何这样的函数都不会被导出到外部,从而不会导致符号冲突

// c++ 示例
class Stack
{
public:
    void Push(int val);
    int Pop();
    bool IsEmpty() const;
private:
    int *mStack;
    int mCurSize;
};
// 纯C API
struct Stack
{
    int *mStack;
    int mCurSize;
};
void StackPush(struct Stack *stack, int val);
int StackPop(struct Stack *stack);
bool StackIsEmpty(const struct Stack *stack);
// 进一步改进
typedef struct Stack *StackPtr;
void StackPush(StackPtr stack, int val);
int StackPop(StackPtr stack);
bool StackIsEmpty(const StackPtr stack);
// 可以通过特定的API调用来完成数据库结构的创建与销毁
StackPtr StackCreate();
void StackDestory(StackPtr stack);

C API的头文件中使用extern "C"限制,以便C++程序能够正确的编译和链接C API

#ifdef _cplusplus
extern "C" {
#endif
// C API声明
#ifdef _cplusplus
}
#endif

面向对象的C++ API

过程式编程、泛型编程、函数式编程

使用面向对象的C++概念创建二进制兼容的API是极为困难的

基于模板的API

模板可以用来编写在编译时生成代码或执行代码的程序(该技术称为元编程)

模板可以在编译时执行一些工作,进而改进运行时性能

#include <vector>
template <typename T>
class Stack
{
public:
    void Push(T val);
    T Pop();
    bool IsEmpty() const;
private:
    std::vector<T> mStack;
};
// 可以定义一个typedef,这样就可以更方便地使用该模板实例了
typedef Stack<int> IntStack;
IntStack *stack = new IntStack();

模板实现方式的另一个选择是,利用C预处理器来定义一段文本,可以将其放入多个头文件中

#include <vector>
#define DECLARE_STACK(Prefix, T) \
class Prefix##Stack \
{ \
public: \
    void Push(T val); \
    T Pop(); \
    bool IsEmpty() const; \
    
private: \
    std::vector<T> mStack; \
}
DECLARE_STACK(Int, int);

模板提供了一种类型安全的在编译时生成代码的方式。你可以调试到类模板的时机代码行中。除非你要编写纯C API,无法使用模板,否则就应该避免使用预处理器来模拟模板

模板的一个重要属性是,不同于使用继承时的动态(运行时)多态,它支持静态(编译时)多态

不会像虚方法那样存在运行时代价

模板进一步的益处,对于特定类型的实例类,可以特化它的某些方法

template <>
void Stack<int>::Push(int val)
{
    // 实现特定于int类型的压栈功能
}

基于模板的API的缺点

  • 最严重的问题是:类模板的定义通常必须出现在公开的头文件中
  • 因为要特化模板,编译器必须能够访问模板代码的完整定义,显而易见,这会暴露内部细节
  • 每当其他文件包含了类模板定义所在的头文件时,内联的代码都需要重新编译,生成的代码会被添加到每个使用该API的模块的目标文件。这会增加编译时间,并致使代码膨胀
  • 实际上有些情况下你可以使用显式实例化技术将模板的实现隐藏在.cpp文件中
  • 模板的另一个缺点是,模板代码中出现错误时,大多数编译器生成的报错信息都是冗长且令人困惑的,可用STLFilt

相对于运行时开销而言,代码体积是需要优先考虑的因素,那么应该选择面向对象方案,而非模板。或者相反,如果运行时性能更为重要,那就应该选择模板

数据驱动型API

数据驱动型程序指的是:通过每次运行时提供不同的输入数据,它可以执行不同的操作

优点

  • 对于API将来可能发生的变化,它的容错性更强
  • 可以更容易地支持数据驱动型测试技术p143

API支持可变参数列表

  • 联合体
  • 继承
  • void *

到此这篇关于C++ API功能设计的实现的文章就介绍到这了,更多相关C++ API内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++中声明、定义、初始化、赋值区别介绍

    C++中声明、定义、初始化、赋值区别介绍

    在 C++ 中,声明、定义、初始化、赋值是变量的四个基本操作,很多朋友不清楚他们之间有什么区别,今天通过本文给大家介绍下C++中声明、定义、初始化、赋值区别,感兴趣的朋友一起看看吧
    2023-05-05
  • VC++的combobox控件用法汇总

    VC++的combobox控件用法汇总

    这篇文章主要介绍了VC++的combobox控件用法,对VC++初学者来说尤为重要,需要的朋友可以参考下
    2014-08-08
  • c++11&14-多线程要点汇总

    c++11&14-多线程要点汇总

    这篇文章主要介绍了c++11&14-多线程的使用方法,文中代码非常详细,方便大家更好的参考和学习,感兴趣的朋友快来了解下
    2020-06-06
  • C++利用容器查找重复列功能实现

    C++利用容器查找重复列功能实现

    本文将详细介绍c++容器简介,c++容器的比较 与操作实例,需要了解更多的朋友可以参考下
    2012-11-11
  • C语言实现简单的计算器

    C语言实现简单的计算器

    这篇文章主要为大家详细介绍了C语言实现简单的计算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-02-02
  • C++树之遍历二叉树实例详解

    C++树之遍历二叉树实例详解

    这篇文章主要给大家介绍了关于C++树之遍历二叉树的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • c++优先队列(priority_queue)用法详解

    c++优先队列(priority_queue)用法详解

    这篇文章主要介绍了c++优先队列(priority_queue)用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • 利用C++编写一个Json解析器

    利用C++编写一个Json解析器

    这篇文章主要为大家详细介绍了如何利用C++编写一个简单又好用的Json解析器,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2023-03-03
  • c++连续输入未知个数的数字操作

    c++连续输入未知个数的数字操作

    这篇文章主要介绍了c++连续输入未知个数的数字操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 举例说明自定义C++异常处理的实例

    举例说明自定义C++异常处理的实例

    这篇文章主要介绍了举例说明自定义C++异常处理的实例的相关资料,这里举例说明该如何使用C++ 的异常,需要的朋友可以参考下
    2017-10-10

最新评论