您的位置:首页 > 编程语言 > C语言/C++

C++之模板

2016-06-17 16:31 411 查看
模板主要应用于泛型编程,现在主要就是非常火的STL(标准模板库),对于公司项目来说利用模板的可能性不大,一般一个项目是无法达到模板这个要求的。

一、函数模板

函数模板的要求是:

1、函数名一致

2、参数个数一致

3、函数体一致

4、参数类型不同

函数模板的格式:

template<class/typename T1, class/typename T2, ...>
返回类型  函数名(参数列表){
函数体
}


举个例子:

template<typename T>
void Swap(T &a, T &b) {
T t = a;
a = b;
b = t;
}

int main() {
int a = 5;
int b = 3;
cout << "a = " << a << ", b = " << b << endl;
Swap(a, b);
cout << "a = " << a << ", b = " << b << endl;

double c = 5.6;
double d = 3.2;
cout << "c = " << c << ", d = " << d << endl;
Swap(c, d);
cout << "c = " << c << ", d = " << d << endl;

string e = "aaa";
string f = "bbb";
cout << "e = " << e << ", f = " << f << endl;
Swap(e, f);
cout << "e = " << e << ", f = " << f << endl;

system("pause");
return 0;
}


输出结果:



利用同一个函数模板可以应用于不同的类型,上面的每一次Swap的调用其实本质都是:

Swap(a, b);   ------>     Swap<int>(a, b);
Swap(c, d);   ------>     Swap<double>(c, d);
Swap(e, f);   ------>     Swap<string>(e, f);


这个过程就是从函数模板转换成模板函数的一个过程, 左边是一种函数模板的隐式实例化,右边是函数模板的显示实例化。

1、函数模板与普通函数重载

template<typename T>
T getmax(T a, T b) {
return a > b ? a : b;
}

int getmax(int a, int b) {
return a > b ? a : b;
}

int main(){
cout << getmax(8,5) << endl;
system("pause");
return 0;
}


对于这样的代码,编译器采用完全匹配的方式调用参数为int类型的函数

int getmax(int a, int b) {
return a > b ? a : b;
}


因为函数模板的编译需要进行两次编译:

第一次:不考虑类型编译;

第二次:匹配类型,生成可调用的二进制文件

在第一次编译的时候编译器就找到了完全匹配的函数,因为不会再进行第二次编译了。

所以当函数模板与普通函数重载时,优先调用完全匹配的普通函数。

2、函数模板与函数模板重载

template<typename T>
T* const& getmax(T* const& a, T* const& b) {
return *a > *b ? *a : *b;
}

template<typename T>
T const& getmax(T const& a, T const& b) {
return a > b ? a : b;
}

int main(){
cout << getmax(5,8) << endl;
system("pause");
return 0;
}


这段代码会调用下面这个模板函数,

template<typename T>
T const& getmax(T const& a, T const& b) {
return a > b ? a : b;
}


当模板函数与模板函数重载时,根据参数列表进行匹配。

二、结构体模板

template<typename T>
struct student
{
T num;
string name;
int age;
};

int main(){
student<int> stu1 = {1239234, "郭靖", 18};
cout << stu1.num << "   " << stu1.name << "   " << stu1.age << endl;
student<string> stu2 = {"xuesheng2", "黄蓉", 16};
cout << stu2.num << "   " << stu2.name << "   " << stu2.age << endl;
system("pause");
return 0;
}


输出结果:



三、类模板

STL中常用的就是类模板,比如vector,stack都是类模板,这里就拿stack为例:

类模板的格式:

template<typename T1, typename T2, ...>
class 类名{
类内部实现;
};


若成员函数在类内部定义则与普通类的成员函数的定义一样, 若成员函数在类外部定义则要这样写,以下面stack的构造函数为例,在函数前不仅要加

template<typename T>


域名要写成这种形式:

MyStack<T>::函数名


自实现的Stack类模板

template<typename T>
MyStack<T>::MyStack(int s) {
size = s;
arr = new T[size];
top = 0;
}


#include<iostream>
#include<string>

using namespace std;

template<typename T>
class MyStack {
public:
MyStack(int s = 1024);
~MyStack();
bool isEmpty();
bool isFull();
void push(T num);
T pop();
private:
T *arr;
int top;
int size;
};

template<typename T> MyStack<T>::MyStack(int s) { size = s; arr = new T[size]; top = 0; }

template<typename T>
MyStack<T>::~MyStack() {
delete[]arr;
}

template<typename T>
bool MyStack<T>::isEmpty() {
return top == 0;
}

template<typename T>
bool MyStack<T>::isFull() {
return top == size;
}

template<typename T>
void MyStack<T>::push(T num) {

arr[top++] = num;
}

template<typename T>
T MyStack<T>::pop() {
return arr[--top];
}

int main() {
MyStack<int> ms;
ms.push(20);
cout << ms.pop() << endl;
ms.push(30);
cout << ms.pop() << endl;
ms.push(10);
cout << ms.pop() << endl;
cout << "-------------------" << endl;
MyStack<string> mstr;
mstr.push("aaa");
cout << mstr.pop() << endl;
mstr.push("bbb");
cout << mstr.pop() << endl;
mstr.push("ccc");
cout << mstr.pop() << endl;

cout << "-------------------" << endl;
MyStack<double> msdou;
msdou.push(1.1);
cout << msdou.pop() << endl;
msdou.push(2.2);
cout << msdou.pop() << endl;
msdou.push(3.3);
cout << msdou.pop() << endl;
system("pause");
return 0;
}


输出结果:



MyStack<int> ms


对于这句代码,是个从类模板转换成模板类,再生成对象的过程。

如果写类模板,最好是先用一种简单的类型写一遍,再把类型替换掉就可以了。

再粘一个自实现的vector的例子,个人认为还是蛮典型的:

#include<iostream>

using namespace std;

template<typename T>
class MyVector {
public:
MyVector(int s = 1024) {
arr = new T[s];
size = 0;
}

MyVector(MyVector<T> &another) {
int len = another.getSize();
arr = new T[len];
for (int i = 0; i < len; i++) {
arr[i] = another.arr[i];
size++;
}
}

MyVector<T>& operator=(MyVector<T> & another) {
if (this == &another)
return *this;
delete[]arr;
int len = another.getSize();
arr = new T[len];
for (int i = 0; i < len; i++) {
arr[i] = another.arr[i];
size++;
}
return *this;
}

T& operator[](int i) {
if (i > size){
cerr << i << "不存在" << endl;
}
return arr[i];
}

~MyVector() {
delete []arr;
}
int getSize() {
return size;
}

void push_back(T num) {
arr[size++] = num;
}

T pop_back() {
return arr[--size];
}

friend ostream& operator<<(ostream& os, const MyVector& mv) {
for (int i = 0; i < mv.size; i++)
os << mv.arr[i] << " ";
return os;
}

private:
T *arr;
int size;
};

int main() {
MyVector<int> mv;
for(int i = 0; i < 10; i++)
mv.push_back(i);
cout << mv << endl;
cout << "------------------------" << endl;

MyVector<double> v2;
for (int i = 0; i < 10; i++)
v2.push_back(i + 0.1);
cout << v2 << endl;
cout << "------------------------" << endl;

MyVector<char> v3;
char c = 'a';
for(int i = 0; i < 10; i++){
v3.push_back(c++);
}
cout << v3 << endl;
cout << "------------------------" << endl;
system("pause");
return 0;
}


输出结果:



四、模板特化

template<typename T1, typename T2>
class Temp {
public:
void func(T1 t1, T2 t2) {
cout << "class Temp " << endl;
}
};

//完全特化
template<>    //这里不能漏掉
class Temp<int, double> {
public:
void func(int t1, double t2) {
cout << "class Temp<int, double>" << endl;
}
};

//局部特化
template<typename T>
class Temp<T, double>{
public:
void func(T t1, double t2) {
cout << "class Temp<T, double>" << endl;
}
};

template<typename T>
class Temp<T, T> {
public:
void func(T t1, T t2) {
cout << "class Temp<T, T>" << endl;
}
};

int main(){
Temp<int, int> temp1;
temp1.func(1, 2);
Temp<int, double> temp2;
temp2.func(1, 2.0);
Temp<float, double> temp3;
temp3.func(1.3, 2.5);
Temp<char, string> temp4;
temp4.func('a', "sfafsa");
system("pause");
return 0;
}


输出结果:



五、模板默认参数

1、类模板默认参数

template<typename T1 = int, typename T2 = double>
class test {
public:
void func() {
cout << typeid(t1).name() << "   " << typeid(t2).name() << endl;
}
private:
T1 t1;
T2 t2;
};
int main(){
test<> test1;    //虽然使用了默认参数,但是<>不能少
test1.func();
test<float> test2;
test2.func();
test<char, int> test3;
test3.func();
system("pause");
return 0;
}


输出结果:



2、函数模板默认参数

template<typename T = int>
void foo(T t) {
cout << typeid(t).name() << endl;
}

int main(){
foo("strsqa");
foo((float)12);
system("pause");
return 0;
}


输出结果:



3、类模板中的成员函数模板

template<typename T1 = int, typename T2 = double>
class test {
public:
template<typename T = int>
void func(T t) {
cout << typeid(t1).name() << "   " << typeid(t2).name() << "   " << typeid(t).name() << endl;
}
private:
T1 t1;
T2 t2;
};

int main(){
test<> test1;
test1.func(1);
test<float> test2;
test2.func((float)1);
test<char, int> test3;
test3.func((double)1);
system("pause");
return 0;
}


输出结果:



总结:

1、模板不是一个完整的类型,使用到类型时要用到尖括号<>。

2、结构体模板和类模板必须使用显示实例化,也就是必须加<>,函数模板可以隐式实例化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: