1、类模板的泛指类型可以定义多个
template
class Test
{
public:
void add(T1 a, T2, b);
};
使用时: Test t1; //T1的泛指类型就是int, T2的泛指类型就是float。
2、类模板的特化类型
(1)意思就是如果定义了一个类模板,这个类模板的参数有多个,但是如果当使用这个类模板的时候,我们传递参数时,参数的类型是一样的话,编译器就会将类模板特化成一个参数的类模板。
(2)类模板的特化分为:部分特化,和完全特化。
部分特化:用特定规则约束类型参数,部分类型参数必须显示指定,根据类型参数分开实现类模板
如:
template 特化后 template
< typename T1, typname T2 > < typename T >
class Test class Test //部分特化的约束条件
{ {
}; };
当类型参数不同的时候,会选择用左边的那个类模板,当类型参数相同的时候。class Test< T, T>就是约束条件
完全特化:完全显示指定类型参数
如:
template 特化后 template
< typename T1, typname T2 > < > //完全特化时,不需要声明泛指类型
class Test class Test //这个就是完全特化
{ {
}; };
当使用类模板的时候,并且指定了所有的类型参数全都是一样的,比如int的时候,编译器就会将左边的类模板特化成右边的类模板,此时该类模板中就没有泛指类型了。
当类型参数不同的时候,就会使用左边的类模板。
(3)根据实验的例子,类模板的特化就是程序中有了一个左边的类模板的时候(这个类模板的有两个泛指类型),但是同时程序中我们又定义了一个同名的类模板,但是这个类模板的两个泛指类型都是一样的。这个时候,当我们在程序中使用这个类模板的时候,如果参数类型是不一样的,编译器就会使用左边的那个,如果参数类型是一样的时候,编译器就会使用右面的那个。编译器会认为右边的那个类模板,是左边的类模板的一种特化,编译器不会认为左边的类模板是一个新的类模板,只是一个左边类模板的一个特化,所以编译能够通过。
总结:将一个类模板,根据不同的类型参数情况进行分开实现这个类模板,其实就是一个类模板的特化过程。
例:
#include
using namespace std;
template
< typename T1, typename T2 >
class Test
{
public:
void add(T1 a, T2 b)
{
cout << "void add(T1 a, T2 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)" << endl;
cout << a + b << endl;
}
void print(void) //即使多出来了个print成员函数,编译也是通过的,所以是支持这种特化方式的
{
cout << "class Test < T, T > " << endl;
}
};
/******************************************************完全特化**********************************************************/
template
< > //进行类模板的完全特化时,不用进行泛指类型的声明
class Test //当使用Test类模板时,参数类型都为void *时,就会使用这个实现。
{
public:
void add(void * a, void * b)
{
cout << "void add(void * a, void * b)" << endl;
cout << "Error run not to add because type is void *..." << endl;
}
};
/*****************************************将Test类模板特化出一个两个参数分别是指针的情况**********************************************/
template
< typename T1, typename T2>
class Test < T1 *, T2 *>
{
public:
void add(T1 *a, T2 *b)
{
cout << "void add(T1 *a, T2 *b)" << endl;
cout << *a + *b << endl;
}
};
int main(void)
{
int a = 1;
double b = 1.0;
Test t1; //使用的就是没有特化的Test类模板
Test t2; //使用的就是特化后的Test类模板
Test t3;
Test t4;
t1.add(2, 2.5);
t2.add(10, 10);
t2.print();
t3.add(&a, &b);
t4.add(&a, &b);
return 0;
}
3、继续理解类模板的特化
(1)类模板的特化的就是根据需要,将一个类模板进行分开来实现。特化只是模板的分开实现,本质上还是同一个类模板。特化类模板的使用方式是统一的,就是必须显示的指定每一个类型参数。
(2)问题:类模板特化与重定义有区别吗?
答:有区别,重定义和特化不同。在本质上,如果将一个类模板进行重定义,那么要么就是实现了一个新的类,要么就是最后会出现两个类模板。本质上不同。使用的时候不能进行统一使用,
在使用时我们要考虑选择哪个。
特化的本质是,只实现同一个类模板,只不过这个类模板是分开来实现的,这就是本质上的不同。在使用时是用统一的方式进行使用类模板和特化类,因为本质上都是实现了一个类模板,使用时
编译器会根据不同的参数类型来选择去使用那个类模板还是特化类。所以类模板的特化就是将一个类模板进行分开来实现,这句话是非常重要的。
(3)问题:函数模板可以特化吗?
答:函数模板只支持类型参数的完全特化,不支持部分特化,也就是在函数名的后面显示的指定出具体的参数类型。
如:函数模板的完全特化
template
< typename T >
bool Equal(T a, T b) //函数模板的定义
{
return a == b;
}
template
< >
bool Equal(void *, void *) //函数模板的完全特化
{
return a == b;
}
(4)工程中的建议:当需要重载函数模板的时候,我们要优先考虑使用模板特化的方式去分开实现一个函数模板,而是不用重载函数模板的方式去新的实现了一个函数,当模板特化无法满足要
求的时候,在使用函数重载。
工程中使用模板特化来代替类(函数)重定义。
例:类模板的部分特化、完全特化,函数模板的完全特化。优先考虑使用特化的方式当需要将模板进行重定义添加功能时。
#include
#include
using namespace std;
/*
* 特化的方式实现一个类模板,本质就是分开实现类模板
*
*/
template
class Why
{
public:
void print(T1 a, T2 b)
{
cout << "void print(T1 a, T2 b)" << endl;
cout << a << " " << b << endl;
}
};
template
class Why //为类模板的部分特化
{
public:
void print(T a, T b)
{
cout << "void print(T a, T b)" << endl;
cout << a << " " << b << endl;
}
};
template
< >
class Why //为类模板的完全特化
{
public:
void print(int a, int b)
{
cout << "void print(int a, int b)" << endl;
cout << a << " " << b << endl;
}
};
/*
* 函数模板的特化只支持完全特化
* 实现一个函数模板,并且完全特化,也就是分开实现一个函数模板,这样叫做特化。
*/
template
bool Equal(T a, T b)
{
return a == b;
}
template
< > //函数模板的完全特化,之所以要特化这个函数模板是因为,浮点数的比较不单纯的只用==来比较。
bool Equal(double a, double b)
{
const double delta = 0.00000000001;
double r = a - b;
cout << "bool Equal(double a, double b)" << endl;
return ((-delta < r) && (r < delta));
}
/*
* 重载Equal函数的方式来达到比较浮点数的方法,但这种方式是不优先考虑的,因为这种方式,在使用的时候要考虑如何选择,要优先考虑使用特化的方式。
* 能使用特化的方式时,就不考虑使用这种函数重载的方式,不论对于类模板还是函数模板都是这样的,优先考虑使用特化的方式来分开实现,因为这样都是为了实现一个类模板或函数模板。
*/
bool Equal(double a, double b)
{
const double delta = 0.00000000001;
double r = a - b;
cout << "bool Equal(double a, double b)" << endl;
return ((-delta < r) && (r < delta));
}
int main(void)
{
double a = 0.0, b = 0.0;
Why w1;
Why w2;
Whyw3;
w2.print("why", "fangqingqing");
w1.print(1, 2.2);
w3.print(100,100);
cout << "Please input two double number..." << endl;
cin >> a >> b;
cout << Equal(a, b) << endl;
cin >> a >> b;
cout << Equal(a, b) << endl;
return 0;
}
网页标题:c++类模板深度剖析
本文路径:
http://cdxtjz.com/article/gpesep.html