1.类模板定义
a.类模板以相同的方式处理不同的类型;
b.在类声明前使用template进行标识。
2.类模板语法规则
template <typename T>
class Operator
{
public:
T op(T a, T b);
};
<typename T> 用于说明类中使用的泛指类型T。
a.和函数模板不同,类模板只能显示指定具体类型,无法自动推导;定义对象时要加<type>
指定具体类型,如下所示。
Operator<int> op1;
Operator<string> op1;
int i = op1.op(1, 2);
string s = op2.op("Hello", "World!");
b.声明的泛指类型T可以出现在类模板的任意地方;
c.类模板必须定义在.h文件中;
d.且不能分开实现在不同的文件中。;
e.类模板外部定义的成员函数需要加上模板<>声明。
3.类模板的应用场景
类模板主要用于存储和组织数据元素的类;类中数据组织的方式和数据元素的具体类型无关;比如:数组类、链表类、Stack类、Queue类等。
C++中将模板的思想应用于类,使得类的实现不关注数据元素的具体类型,而只关注类所需要实现的功能。
4.编译器如何编译函数模板
编译器对类模板的处理方式和函数模板相同。
a.编译器根据类模板的具体类型产生不同的类;
b.编译器会对函数模板进行两次编译,首先在声明的地方对类模板代码本身进行编译,然后在使用的地方对参数替换后的代码进行编译。
5.类模板的使用
下面给出类模板的初步使用:
Operator.h
#ifndef _OPERATOR_H_
#define _OPERATOR_H_
template < typename T >
class Operator
{
public:
T add(T a, T b);
T minus(T a, T b);
T multiply(T a, T b);
T divide(T a, T b);
};
template < typename T >
T Operator<T>::add(T a, T b)
{
return a + b;
}
template < typename T >
T Operator<T>::minus(T a, T b)
{
return a - b;
}
template < typename T >
T Operator<T>::multiply(T a, T b)
{
return a * b;
}
template < typename T >
T Operator<T>::divide(T a, T b)
{
return a / b;
}
#endif
main.cpp
#include <iostream>
#include <string>
#include "Operator.h"
using namespace std;
int main()
{
Operator<int> op1;
cout << "op1.add(1, 2) = " << op1.add(1, 2) << endl;
cout << "op1.multiply(4, 5) = " << op1.multiply(4, 5) << endl;
cout << "op1.minus(5, 6) = " << op1.minus(5, 6) << endl;
cout << "op1.divide(10, 5) = " << op1.divide(10, 5) << endl;
return 0;
}
运行结果如下所示:
6.多参数类模板
类模板可以定义任意多个不同的类型参数, 如下所示:
template <typename T1, typename T2>
class Test
{
public:
void add(T1, a, T2 b);
};
Test<int, float> t; // 定义对象
7.类模板特化
类模板可以被特化:
a.指定类模板的特定实现;
b.部分类型参数必须显示指定,比如返回值类型必须显示指定;
c.根据类型参数分开实现类模板。
d.类模板的特化可以分为:
部分特化:用特定规则约束类型参数;
完全特化:完全显示指定类型参数。
e.模板特化注意事项:
特化只是模板的分开实现 ,本质上是同一个类模板;
特化模板的使用方式是统一的,必须显示指定每一个类型参数。
下面给出模板特化的示例:
#include <iostream>
#include <string>
using namespace std;
template < typename T1, typename T2 >
class Test
{
public:
void add(T1 a, T2 b)
{
cout << "void add(T1 a, T2 b) = " << a + b << endl;
//cout << a + b << endl;
}
};
template < typename T1, typename T2 >
class Test < T1*, T2* > // 关于指针的特化实现
{
public:
void add(T1* a, T2* b)
{
cout << "void add(T1* a, T2* b) = " << *a + *b << endl;
//cout << *a + *b << endl;
}
};
template < typename T >
class Test < T, T > // 当 Test 类模板的两个类型参数完全相同时,使用这个实现
{
public:
void add(T a, T b)
{
cout << "void add(T a, T b) = " << a + b << endl;
//cout << a + b << endl;
}
void print()
{
cout << "class Test < T, T >" << endl;
}
};
template < >
class Test < void*, void* > // 当 T1 == void* 并且 T2 == void* 时
{
public:
void add(void* a, void* b)
{
cout << "void add(void* a, void* b)" << endl;
cout << "Error to add void* param..." << endl;
}
};
int main()
{
Test<int, float> t1;
Test<long, long> t2;
Test<void*, void*> t3;
t1.add(1, 2.5);
t2.add(5, 5);
t2.print();
t3.add(NULL, NULL);
Test<int*, double*> t4;
int a = 1;
double b = 0.1;
t4.add(&a, &b);
return 0;
}
运行结果如下图所示:
8.数值型参数
模板参数可以是数值参数(非类型参数),格式如下:
template <int N>
class
{
public:
static const int value = N;
};
模板参数是在编译阶段被处理的单元,因此模板参数必须在编译阶段必须准确无误的唯一确定,下面列出数值型模板参数的限制:
1.变量不能作为模板参数;
2.浮点数不能作为模板参数;
3.类对象不能作为模板参数。
总之,一切在编译阶段无法确定的参数均不能作为模板参数。
下面是一道面试题:
用你觉得最高效的方法求1+2+3+...+N的值!
下面通过模板数值型参数给出解答:
#include <iostream>
using namespace std;
template <int N>
class Sum
{
public:
static const int value = Sum<N-1>::value + N;
};
template < >
class Sum <1>
{
public:
static const int value = 1;
};
int main()
{
cout << "1+2+3+...+10 = " << Sum<10>::value << endl;
cout << "1+2+3+...+100 = " << Sum<100>::value << endl;
return 0;
}
Sum::value的值在编译的时候就已经确定了,因此用此方法应该是最高效的了,下面为运行结果: