template模板:泛型化编程

一.在函数中使用模板:

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

类格式为:

template <class 形参1> 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 <class T>
int f(T t)
{
	return t + 1;
}
然后直接可以:

cout<<f(10)<<endl;

其输出值为11。

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

如上面的YuTest,需要这样调用:YuTest<int>m_yuTest;或YuTest<CString>m_yuTest;

 

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

typedef  YuPointT<int>     YuPoint;

 

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

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

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

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

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

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

template<typename T >	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 <class T>
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;时就会出错。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值