template

template的使用大大提高了代码的复用性, 抽象性

  1. 类模板实例化时并不是每个成员函数都实例化了, 而是使用到了哪个成员函数, 那个成员函数才实例化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* ***** 1 *******/
template<class T>
class point
{
public:
point() : x(0), y(0) {}
point(T x, T y) : x(x), y(y) {}
T getX() const { x = y; return x; } // 一般是无法通过编译的, x不允许被修改, 但是这里并没有报错
private:
T x;
T y;
};
/* ***** 2 *******/
#define T int
class point
{
public:
point() : x(0), y(0) {}
point(T x, T y) : x(x), y(y) {}
T getX() const { x = y; return x; }
private:
T x; T y;
};

成员函数getX()应该无法通过编译, 就像实例2一样, 但是因为模板中没有使用到函数getX(), 也就没有实例化getX, 所以就没有出现编译报错. 实例2必须在编译的时候就要检查所有的成员即函数.

不是所有的模板都只能在运行时才会被实例化, 比如非类型模板参数就能在编译时期就已经实例化了, 这里主要说的是类模板, 不要混淆了

  1. 可以把类模板和函数模板结合起来, 定义一个含有成员函数模板的类模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
template<class T>
class point
{
public:
point() : x(0), y(0) {}
point(T x, T y) : x(x), y(y) {}
template<class U> // 定义了另一个的模板参数类型
void print(U x);
private:
T x;
T y;
};

// 这里两个都要写出来
template<class T>
template<class U>
void point<T>::print(U x)
{
std::cout << this->x + x;
}

int main()
{
point<int> p;
p.print(3.14); // 因为是模板函数, 所以交给编译器自行推导

exit(0);
}

3. 类模板中可以声明static成员, 在类外定义的时候要增加template相关的关键词, 并且需要注意每个不同的模板实例都会有一个独有的static成员对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;

template <class T> class tmp {
public:
static T t;
};

template <class T> T tmp<T>::t = 0;

int main() {
tmp<int> t1;
tmp<int> t2;
tmp<double> t3;
t1.t = 1;
cout << "t1.t = " << t1.t << endl;
cout << "t2.t = " << t2.t << endl;
cout << "t3.t = " << t3.t << endl;

exit(0);
}

输出结果:

1
2
3
t1.t = 1
t2.t = 1
t3.t = 0

模板中的static是在每个不同的类型实例化一个, 相同类型的实例化对象共享同一个参数。所以这里的t1, t2中哦t都是同一个实例化变量, 是共享的。