C++ 泛型编程

什么叫泛型编程?

泛型编程是一种新的编程思想,基于模板技术有效的将算法和数据结构分离,编写不依赖具体数据类型的程序,将程序尽可能通用,将算法从数据结构中抽象出来,成为通用算法。C++中模板为泛型程序设计提供了基础,STL(标准模板库Standard Template Library)是泛型程序设计的例子。

模板概念

模板是一种用不确定类型参数来产生一系列函数和类的机制,通过模板我们可以产生类和函数的集合,使他们操作不同的数据类型,从而避免为每一种数据类型单独产生一个函数和类,模板分为函数模板和类模板。

模板只是说明,需要实例化之后才能执行和使用


函数模板

 函数模板使用和普通函数一样,但它的类型可以通过参数来传递,在函数定义时可以不指明具体的数据类型,当发送函数调用时,编译器可根据传入的实参自动推断数据类型。

语法:

template <<模板参数表>>
<返回值类型><函数名>(<参数表>){
              <函数体>
}
template:函数模板定义关键字
<模板参数表>:用来定义函数参数的类型,参数类型有一个或多个,用逗号隔开,不能为空,模板参数常用形式 typename class 

为何要用到函数模板?
举例:交换两个数的方法
宏定义:

优点:代码复用,适合所有的类型
缺点:缺少类型检查,宏在预处理阶段被代替掉,编译器不知道宏的存在


函数:

优点:真正的函数调用,编译器对类型进行检查
缺点:类型不同时需要重复定义函数,代码无法复用

函数模板:

优点:代码复用,适合所有类型。克服普通函数弊端,编译器会进行类型检查。克服宏定义弊端
缺点:调试比较难,对程序员要求高,—般编写一个类型确定的函数,运行通过后,再修改成函数模板
调用方式:1.自动类型推导调用    swap(a, b); 1.具体类型显示调用(推荐使用)Swap<int>(a, b);

 注意:函数模板不允许隐式类型转换,调用时类型必须严格匹配

原理分析: 函数模板中声明了参数类型T,表示了一种抽象类型,编译器检查到程序调用函数的时候,根据传递参数的实际类型生成模板函数。

类模板

定义:

是对一批仅仅成员数据类型(成员函数和程序数据)不同的类的抽象,程序员只要为这一批类所组成的整个类家族创建一个类模板,给出一套程序代码,就可以用来生成多种具体的类。

类模板定义格式:

template <<模板参数表>>class <类模板名>
{
     <成员函数与成员变量>
};
成员函数在类外定义格式:

template <<模板参数表>>
<返回值类型><类模板名><<模板参数名列表>>:;<成员函数名>(<参数表>){
<函数体>
}

类模板定义对象:

类模板名<真实类型参数表>对象名(构造函数实际参数表)


原理:编译器由类模板生成类的过程叫做类模板的实例化,编译器自动用具体的数据类型替换类模板中的类型参数,生成模板类的代码,由类模板实例化得到的类叫做模板类。

类模板与非类型参数
template <class T, int elementsNumber>    elementsNumber 不能是浮点类型,不能是类类型!

示例:顺序表

类定义:

#include<iostream>
#include<cstring>

using namespace std;

template <typename T,int size>
class SeqList
{
public:
	SeqList();
	~SeqList();

	bool addData(T value);
	bool delData();

	void show();
	void clear();
private:
	T *data;
	int index;
};

构造函数与析构函数实现:

template <typename T,int size>
SeqList<T,size>::SeqList() 
{
	data = new T[size];
	index = 0;
}
template <typename T,int size>
SeqList<T,size>::~SeqList()
{
	delete []data;
}

添加数据函数和删减数据函数实现:

template <typename T,int size>
bool SeqList<T,size>::addData(T value)
{
	if(index >= size)
	{
		cout << "顺序表已满" << endl;
		return false;
	}
	data[index] = value;
	index++;
	return true;
}

template <typename T,int size>
bool SeqList<T,size>::delData()
{
	if(index > 0)
	{
		--index;
		return true;
	}
	return false;

}

遍历顺序表实现:

template <typename T,int size>
void SeqList<T,size>::show()
{
	for(int i = 0; i< index; ++i)
	{
		cout << data[i] << " ";
	}
	cout << endl;
}

清空函数实现:

template <typename T,int size>
void SeqList<T,size>::clear()
{
	index = 0;
}

主函数调用:

int main(int argc, const char *argv[])
{
	SeqList <int,5>A;
	A.addData(1);
	A.addData(2);
	A.addData(3);
	A.addData(4);
	A.addData(4);
	A.addData(4);
	A.addData(4);
	A.delData();
	A.delData();
	A.show();
	return 0;

二次编译机制:

在编译器进行编译的时候,编译器会产生类的模板函数的声明,当时实际确认类型后调用的时候,会根据调用的类型进行再次帮我们生成对应类型的函数声明和定义。
二次编译机制在模板类中声明友元函数,且函数实现在类外时会因为编译器找不到友元函数的实现而报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值