1.文件的编译和链接
1.1编译
编译过程分为预处理、编译、汇编三个阶段。
预处理
预处理包括宏替换,删除注释,头文件展开,条件编译等操作。最后生成(.i)文件
编译
编译过程包括语法分析,词法分析,语义分析,符号汇总等过程。将编程语言转化为汇编代码,最后生成(.s)文件。
汇编
汇编过程包括汇总符号表,并将汇编代码转换为二进制的机器指令,最后生成(.o)文件。
1.2链接
- 合并段表。
- 符号表的合并和符号表的重定位。其中大部分的编译错误都是因为符号表出现了问题。
- 链接过程将所有的(.o)文件和静态库链接在一起。
2.函数模板
函数模板代表一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特点
2.1函数模板格式
template<typename T1, typename T2,…,typename Tn>
template<class T>
void Swap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 10;
int b = 20;
Swap(a, b);
return 0;
}
**查看汇编代码 **
模板实例化了一个Swap< int >函数
自定义类型使用函数模板
class tmp
{
public:
tmp (int aa = 1, int bb = 1)
:_aa(aa)
, _bb(bb)
{}
tmp operator+(tmp& m)
{
tmp t;
t._aa = _aa + m._aa;
t._bb = _bb + m._bb;
return t;
}
private:
int _aa;
int _bb;
};
template<class T>
T add(T& a, T& b)
{
return a + b;
}
int main()
{
tmp m(2, 3);
tmp n(2, 1);
tmp res = add(m, n);
return 0;
}
2.2函数模板的显示实例化
template<class T>
T Add(const T&left,const T&right)
{
return left+right;
}
int main()
{
int a=10;
double d1=20.0;
Add<int>(a,b);
return 0;
}
2.3非模板函数和同名函数模板的调用顺序
需要注意的是:对于非模板函数和同名函数模板,如果其他条件相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例,如果模板 可以产生一个具有更好匹配的函数,那么将选择模板
3.类模板
template<class T>
class Vector {
public:
Vector(int capacity = 10, int size = 0)
:_a(new T[capacity])
, _capacity(capacity)
, _size(size)
{}
~Vector();
void Pushback(const T& m);
void Popback();
T& operator[](int pos)
{
return _a[pos];
}
private:
T* _a;
int _capacity;
int _size;
};
template
class Vector<int>;
template<class T>
Vector<T>::~Vector() {
if(_a)
delete[] _a;
_capacity = _size = 0;
}
int main()
{
Vector<int>v(10, 0);
return 0;
}
类模板的实例化与函数模板实例化不同,类模板实例化需要在类模板名字后面加上<实例化类型>
类模板中函数放在类外进行定义时,需要加模板参数列表
template<class T1,class T2,class T3......>
Vector<T1,T2,T3.....>::~Vector() {
if(_a)
delete[] _a;
_capacity = _size = 0;
}
4.模板声明和定义分离的情况
模板不支持声明和定义放到两个文件中的。会出现链接错误
方法一:将模板的定义和声明放在,hpp文件下
template<typename T>
void Swap(T& left, T& right);
template<class T>
class Vector
{
public:
Vector(size_t capacity = 10);
void PushBack(const T& x);
private:
T* _pData;
size_t _size;
size_t _capacity;
};
//定义
template<typename T>
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
template<class T>
Vector<T>::Vector(size_t capacity)
: _pData(new T[capacity])
, _size(0)
, _capacity(capacity)
{}
template<class T>
void Vector<T>::PushBack(const T& x)
{
// ...
}
方法二:将需要使用的函数和类都进行实例化
#include "template.h"
template
void Swap<int>(int& left, int& right);
template
class Vector<int> ;
template
class Vector<double> ;
模板声明和定义不能放在两个文件的原因
首先需要明确,链接就是要找到函数,类等的地址。而对于模板来说,仅仅是提供一个范式,并没有在内存中开辟空间,所以也没有相应的地址。
如果定义和声明分开,在链接汇总符号表时,无法找到函数模板和类模板对应的地址,所以会出现链接错误。