template模板:泛型化编程

一.在函数中使用模板:

template <typename形参1,typename形参2> int compare(const形参1&a,const形参2&b);

类格式为:

template  class YuTest
{
public:
	形参1 GetNum();
	……
}
注意:

1.每个模板形参都必须有关键字typenameclass来修饰。不可以漏写。

如:       template<typenameT,U> 的写法是错误的。

2.模板形参有两种:①类型化形参,该种形参接收一个类对象,可以用typenameclass来修饰;②非类型形参,或者说常量表达式形参,该种形参接收一个常量,可以用typenameclass来修饰。

typenameclass两个关键字的区别在于,class使用更早,故早期版本主要使用class

3.每个模板形参个数并非是任意定义的。一旦定义,后面的函数参数中或类的实现中就必须要用到,否则会编译出错。

4.多个模板形参的名称必须不同。如:template <typenameT,typename T>这样的写法是错误的

4.每个template只对其后的一个函数或类起作用

5.模板类的声明和实现就目前的编译器而言,必须都在h文件里写。无论是模板类型还是模板函数都是如此。若是模板类,则其成员函数实现也都要在.h中实现。

6.模板函数定义与模板类型方式相同。使用的时候当做一个正常的函数直接调用函数名即可,无需其他操作

template 
int f(T t)
{
	return t + 1;
}
然后直接可以:

cout<

其输出值为11。

7.使用模板类必须显示地为模板形参指定参数。

如上面的YuTest,需要这样调用:YuTestm_yuTest;或YuTestm_yuTest;

 

技巧:使用关键字typedef为每一个类型定义一个别名,使用时直接引用别名。

typedef  YuPointT<int>     YuPoint;

 

二.在类中使用template,有两种方式:

①类中有多个成员函数及成员变量是template类型,那么该类就称之为模板类,需要在类定义前加template <typename形参1>

template 
class YuTest
{
public:
	形参1 GetNum();
	……
}
实现:

template	YuTest <形参1>::GetNum()
{
}

②类中只有1个成员函数是template类型,那么只需要在函数前加template <typename形参1>即可:

class YuTest
{
public:
	template 
	T  GetNum(T p1);
	……
}
实现:

template	YuTest < T >::GetNum()
{
}

三. template 的编译是直到调用时才进行的

       编译器在遇到template的实现时并不为其产生机器代码,而是等到template被指定某种类型时才会编译。

       因此,以下调用是合法的:

class A
{
public:
	A() { x = 1; }
	int x;
};

class B
{
public:
	B() { x = 2.0; }
	double x;
};

class C
{
public:
	C() { x = 3.0; }
	float x;
};

template 
int f(T t)
{
	int a;
	k = (int)t.x;//注①特别注意这里,见下文解释
	return k;
}

void main()
{
	A a;
	B b;
	C c;

	cout << f(a) << endl;
	cout << f(b) << endl;
	cout << f(c) << endl;
}
 如上,一般来说, template所指定的类型 T可以是任何类型。直接使用该类型是可以的。但调用一个未知类型的成员变量或者成员函数是否也可以?

       就如同注①那样,函数f()传入的参数是一个未知类型T,但在函数内却使用了的成员变量x。但T的类型未知,编译器如何知道该类型内是否有成员变量x?

       首先,这样使用是合法的。对于上面的程序而言,编译也会通过并顺利运行。

       其原因就是编译器在遇到template的实现时并不为其产生机器代码,而是等到template被指定某种类型时才会编译。当在main()中运行cout<<f(a)<<endl;时,就会把a赋给T,此时编译器便会编译一次f()的代码,用a将其中的T全部替换。编译f()中的k = (int)a.x;时,顺利通过。同理,运行cout<<f(b)<<endl;时,编译器会编译第二次f()的代码。整个程序结束,编译器会将f()编译三次。

       若将cout<<f(c)<<endl;改为cout<<f(9)<<endl;,当编译器通过了前两次f()的编译,来对该行代码进行编译时,发现其参数9是个int型,而int并无x成员变量,于是在编译k = (int)9.x;时就会出错。

       编写程序时,若需要使用以上的写法,无法使用自动补全功能,也就是靠使用”.”或者”->”是无法自动补全成员变量或成员函数的。因此需要手动填写。只要保证函数内所有涉及的操作在传入的参数类中均有实现即可。

你可能感兴趣的:(C++,C,template,模板,泛化)