C++ API
Colin-YYYY 人气:0前言
创建类来表示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 *
加载全部内容