在绝大多数时候,咱们都不须要从头从新造轮子,直接使用别人封装好的库会让开发变得更高效、更易于管理复杂项目。本文将简单介绍静态连接库的基本技术。ios
很好,若是有人跟你说这种话,那么请让他在无论用什么编程语言的时候都本身实现标准输入、标准输出功能;并且,必定要让他本身写出本身用的操做系统,让他本身写出BIOS芯片组的固件程序……这种人,怼之,使其滚之,敬而远之。程序员
在一个特定的项目里,能够用形形色色的头文件来管理类与函数的声明,可是局限性也很容易被看出来。首先,为了更有效的在以后的项目中使用头文件,那么天然会针对每一种类或函数去书写一份头文件,这就会致使头文件的数量变得不少;并且头文件是不参与编译的,为也能让项目编译经过,还要再把对应的实现源文件也引入到工程中。最重要的一点是保密性。头文件和源文件若是要给别人使用,那么别人都是能够直接修改源码的,尽管我本人是开源的支持者,但咱们并不能保证每一个人都是会遵照开源协议的。编程
这点确实没错,可是用库的最大优点在于,库是编译过的,库只参与生成应用程序的连接过程——这也就是“连接库”这个名字的来历。数组
以上总结了常见的对库持怀疑态度的人的见解,下面说一下为何仍是要推崇库。编程语言
使用库,程序开发者能够不用去操心这个库是怎么实现的——并非说程序开发者必定不会去实现那些他要用到的功能,只是在工程开发中,没有必要再去实现,由于写重复代码是最低效的开发方式——即便那些重复的部分具备至关高的技术含量。
借助已有的库,咱们能够把工做重心转移到更高级的功能开发上去,而不是成天抱着轮子去嘲讽跑车。函数
既然咱们会想到把颇有技术含量并且还又是不少人都会用到的功能写成库以便再次使用,那么有商业头脑的人天然也能想获得。库是编译器编译事后的产物,对于C++来讲,编译是不可逆的——就算是有逆向工程,那么不可能百分百还原,尚且逆向还都是靠有经验的程序员去猜编译前可能会是什么样子的。使用库咱们就能够很好的隐藏本身的实现细节,而只把预留的接口给用户(指使用库的程序员)。
若是哪天咱们本身写出了一套至关具备商业价值的库,咱们一样可使用库的方式来发布、售卖咱们的技术。工具
由于库的编译过的,因此使用库而不是直接引入源代码在编译大型项目时会大大提升编译效率。测试
静态库是编译产生的二进制文件,在使用静态库的程序的最终编译过程当中,连接器从库中复制这些函数与数据并把它们和应用程序的其余模块组合起来,生成可执行文件。库是不能够被执行的——或者说,库没有执行这个概念。
本文以Windows平台为例讲解,虽然中间步骤与Linux相差很大,可是学会了静态库的基础知识后,在其余平台的使用其实也换汤不换药。
由于静态库是编译事后的产物,因此用户是无法知道库中的实现信息的,但这也致使了一个问题:库中的函数和类用户也是不知道如何调用。为了绕开这个问题,咱们能够利用C++中把声明与实现分离的技巧,给库配备一个面向用户的用于声明接口的头文件。下面咱们先建立一个静态库:spa
而后咱们看一下这个静态库项目的属性:操作系统
能够看到,编译后生成的将是一个.lib
文件。
下面咱们来看看把函数装进静态库以便实现代码重用。
先在项目中新建一个头文件:InitializeArray.h
以及对应的源文件:InitializeArray.cpp
,而后在头文件中加入咱们要实现的函数的声明:
(代码格式问题,上图,凑合看吧)
而后在源文件中实现这个函数:
而后咱们选择“生成StaticLibrary”(StaticLibrary是我这里使用的项目的名字),如图:
方法一:(先选中项目,再点击工具栏上的按钮)
方法二:(先选中项目,再使用菜单栏上的命令)
这样咱们就获得了编译事后的静态连接库文件,在解决方案文件夹下的Debug(或者Release)文件夹中能够找到咱们须要用到的静态库:
接下来咱们测试一下编译生成的静态库,顺便看一下如何在程序中使用。在另外一个项目中,咱们须要将静态库文件引入到工程内,我这里将库拷贝到项目目录中的lib
文件夹内:
咱们还要把刚刚编写有函数声明的头文件一块儿放到工程目录下,我这里放到项目目录中的include
文件夹内:
有两种方法能够通知连接器在连接过程当中将咱们的静态库连接进来,下面分别给出:
方法一:在项目属性中设置连接器
方法二:在代码中显示地连接
我我的比较喜欢使用代码进行控制,由于这种方式更直白,更容易看出程序使用了第三方的静态库。
而后咱们就能够在用来测试的项目中编写测试代码来使用刚刚编译的静态库了:
运行效果以下:
下面咱们来试着把类装进静态库中。咱们来实现一个整数类Integer
:
#include <vector> #define VISIBLE_BEGIN #define VISIBLE_END class Integer { VISIBLE_BEGIN public: Integer(); Integer(int integer); Integer(const Integer &); ~Integer(); //判断整数是否为奇数 bool IsOdd(); //判断整数是否为偶数 bool IsEven(); //将整数分解质因数 void Decomposition(std::vector<int> *pVec); //将整数逆序重组 int Reverse(); //取绝对值 int Abs(); //取两数较大者 static int GetMaximum(int numberOne, int numberTwo); //取两数较小者 static int GetMinimum(int numberOne, int numberTwo); //获取不大于整数的全部质数的集合 static void GetPrimeArray(unsigned int integer, std::vector<int> *pResult); //取两数最大公因数 static int GCD(unsigned int numberOne, unsigned int numberTwo); //取两数最小公倍数 static int LCM(unsigned int numberOne, unsigned int numberTwo); //将整数隐示转换为int operator int(); private: bool m_bNegative; long m_lInteger; VISIBLE_END };
关于这个类怎么实现,留给你们讨论。我直接把测试代码及其运行效果给出:
#include "./include/InitializeArray.h" #include "./include/Integer.h" #include <iostream> using namespace std; #pragma comment(lib, "./lib/StaticLibrary.lib") int main() { cout << "输入数组元素个数:"; int size; cin >> size; int *arr; InitializeArray(arr, size); for (int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl; cout << "输入一个整数:"; cin >> size; Integer integer(size); cout << "输入另外一个整数:"; cin >> size; cout << integer << " 和 " << size << "的最小公倍数为 " << Integer::LCM(integer, size) << endl << "将" << integer << "分解质因数结果为:"; vector<int> res; integer.Decomposition(&res); for (vector<int>::iterator iter = res.begin(); iter != res.end(); iter++) { cout << *iter << " "; } cout << endl; return 0; }
别忘了把最新编译生成的静态库和头文件按以前的操做添加到工程目录中。
程序的运行效果以下:
静态库是完成代码重用的很是重要的一种手段,应用程序中每每都会大量使用静态库。本文演示的只是将C++中的一部分特性写进静态库,关于更多的技巧,请自行查阅更多资料。
固然,静态库也有不少缺点,并且,当库中的代码量很大但咱们却不须要所有用到的时候,或者是咱们想更灵活地使用库,那么这个时候咱们就要用到使用更为复杂也支持更多特性的另外一种库——动态连接库。关于动态连接库,下一篇文章将会介绍。