模板

1、什么是模板?

    模板是泛型编程的基础,泛型编程是指编写与类型无关的逻辑代码,是一种复用的方式。分为模板函数和模板类。

2、模板函数、模板类

1)模板函数

模板是与类型无关的编程,模板函数的基本使用方法是:

template <class 形参名1, class 形参名2, class 形参名n>
返回类型 函数名(参数列表)
{...}

注:class还可以用typename

例如:在没学习模板函数前,当我们要交换两个数据时,如果是整型,要定义一个整型的交换函数;如果又有别的类型的数据要进行交换,就要在定义上面定义的交换函数的重载,...这样,我们就要定义很多这样的函数。

void Swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
	return;
}
void Swap(float& a, float& b)
{
	float tmp = a;
	a = b;
	b = tmp;
	return;
}

        但如果使用模板函数就可以不用这样麻烦:

template <class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
	return;
}
int main()
{
	int a = 2;
	int b = 8;
	printf("a=%d b=%d\n", a, b);
	Swap(a, b);
	printf("a=%d b=%d\n", a, b);

	float c = 1.234;
	float d = 34.8;
	printf("c=%f d=%f\n", c, d);
	Swap(c, d);
	printf("c=%f d=%f\n", c, d);
	system("pause");
	return 0;
}

可以看到,已经交换成功了。那么它的原理究竟是什么呢?

我们来看一张推演图:


结论(原理):编译调用模板函数时,编译器会自动推演出传递参数的类型,并自动生成相应的代码。

模板函数的重载:

template <class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
	return;
}
template <class T>
void Swap(T* a, T* b)
{
	T tmp = *a;
	*a = *b;
	*b = tmp;
	return;
}
int main()
{
	int a = 2;
	int b = 8;
	Swap(a, b);
	
	Swap(&a, &b);
	system("pause");
	return 0;
}

2)模板类

类模板的格式

template<class 形参名1, class 形参名2, ...class 形参名n>
class 类名
{ ... };


模板类的原理


模板参数--实现容器适配器

以实现栈为例:

定义容器适配器格式为:

template <class T, class Container>
template <class T, class Container = SeqList<T > > // 缺省参数

template <class T, class Container=Vector<T> >
class Stack
{
public:
    void Push(T x)
    {   
        _con.PushBack(x);
        return;
    }   
    void Pop()
    {   
        _con.PopBack();
        return;                                                                                                                      
    }
    const T& Top()
    {
        return _con.Back();
    }
    int Empty()
    {
        return _con.Size() == 0 ? 1 : 0;
    }

protected:
    Container _con;
};

模板的模板参数--实现容器适配器

在上面的例子中,如果在定义对象时,传入的参数T与Vector的T不一致,就会编译出错。为了避免这样的问题,出现了模板的模板参数的概念:

template <class T, template <class> class Container = SeqList > // 缺省参数

它的原理如下:



3、非类型模板参数

非类型模板参数,顾名思义,就是不是类型的模板参数,通常是一个常量,在静态顺序表中可以用来定义表的最大长度;

//template<typename T, size_t MAX_SIZE>
template <typename T, size_t MAX_SIZE = 10> //带缺省模板参数
class SeqList
{ p
ublic :
SeqList();
private :
T _array [MAX_SIZE];
int _size ;
};
template <typename T, size_t MAX_SIZE>
SeqList <T, MAX_SIZE>::SeqList ()
: _size(0)
{}
void Test ()
{
SeqList<int > s1;
SeqList<int , 20> s2;
}

也可以作为函数的参数,比如一个数总是要加上一个常数,就可以使用非类型的模板参数:

template <class T, int value>
T Add (const T& x )
{
return x + value;
}

值得注意的是,非类型的模板参数不能是浮点型或自定义类型。

4、模板的分离编译

当我们在使用模板时,如果他的声明和定义是一起的,那并不会有什么问题:

//test.h

#pragma once
#include <iostream>
using namespace std;

template <class T>
void hello(T x)
{
	cout << x << endl;
	cout << "hello" << endl;
}

//main.cpp

#include "test.h"
int main()
{
	hello(1);
	system("pause");
	return 0;
}

可若是声明与定义分离,即不在一个文件,会怎么呢?

//test.h

#pragma once
#include <iostream>
using namespace std;

template <class T>
void hello(T x);

//test.cpp

template <class T>
void hello(T x)
{
	cout << x << endl;
	cout << "hello" << endl;
}

//main.cpp

#include "test.h"
int main()
{
	hello(1);
	system("pause");
	return 0;
}

我们发现会编译不能通过:


这是为什么呢?

答:模板不支持分离编译。

那么怎么解决这个问题呢?

  • 不要使定义和声明分离
  • 将含有定义的.cpp文件包含进main.cpp中
  • 模板的显示实例化

  类模板的显示实例化:在类声明的后面加上template class 类名<T的类型>;

  函数模板的显示实例化:在函数声明(以上面的例子为例)后面加上template void hello<int> ();





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值