【C++面向对象】泛型编程(模板) 新手小白都能懂!

泛型编程是什么?

顾名思义,“泛型”即“广泛的类型”,即不拘泥于一种特定类型的编程方法。在泛型编程时,我们通常使用一个或多个类型占位符来表示一种或多种类型,这些类型对于模板而言就像是函数的参数一样,调用时都是不可或缺的(新版本的C++标准中加入了函数模板隐式实例化的定义,系统会根据函数参数推导模板类型参数)。

为什么要使用泛型编程呢?原因很简单,在面对不同的参数类型要实现相同的功能时,频繁进行函数重载会显得非常低效。此时不妨使用泛型编程,它会使得代码可读性和效率大幅提升。

模板和泛型编程的关系?

模板是泛型编程实现的重要手段。声明一个类/函数是类模板/函数模板,需要使用template关键字。下文主要介绍模板的基本方法和技巧,进阶的技巧可以期待 我以后的文章。

模板分为函数模板类模板。下文将逐一介绍它们的使用方法。

函数模板

定义

声明一个函数是函数模板的框架如下:

template <typename T>
func_type func_name(parameter list)
{
	function body;
}

其中,template是关键字;typename是模板类型参数的占位符(也可用class代替);T是我们自主定义的类型名占位符,可以用任何符合规定的标识符替代;func_type是函数返回类型;func_name是函数名;parameter list是函数参数列表(参数不一定都必须是定义的类型占位符类型,但一般情况下都会保留至少一个不是基本类型的参数虽然一个不留也不会错,但这样你还用模板干嘛 );function body是函数内容。

为了更好地理解函数模板,以下是一个函数模板的实例:

template <typename T>
bool compare(T a, T b)
{
	return a > b;
}
调用

以下是一个调用函数模板的实例:

#include <iostream>
using namespace std;

template <typename T>
bool compare(T a, T b)
{
	return a > b;
}

int main()
{
	cout << "5" << (compare <int>(5, 6) ? ">" : "<=") << "6" << endl;
	cout << "0.75" << (compare <double>(0.75, 0.333) ? ">" : "<=") << "0.333" << endl;
	cout << "a" << (compare('a', 'A') ? ">" : "<=") << "A" << endl;
	return 0;
}

运行上面的代码,将会输出以下结果:

5<=6
0.75>0.333
a>A

观察上面的代码,第一、二个输出展现的是显式实例化,即在调用函数时直接指定模板中T的具体指代。而第三个输出展现的是隐式实例化,即在调用函数时不直接指定T,而是让系统在编译时根据参数的类型推导出模板类型参数。

顺便扯一嘴,虽然看起来它们都是调用了同一个函数,但其实通过汇编代码就能发现,编译器产生了不同的函数,感兴趣的读者可以自己研究一下。

请注意:隐式实例化是现代C++标准的内容,部分年代久远的编译器可能不支持,请慎用。另关于实例化的内容会在以后的文章中讲解。

类模板

定义

类模板的声明与函数模板相似,请直接看下面一个实例:

template <typename T>
class oper
{
private:
	T a, b;

public:
	oper() {};
	oper(T ia, T ib)
	{
		this->a = ia;
		this->b = ib;
	}
	~oper() {};

public:
	bool compare()
	{
		return a > b;
	}

	T add()
	{
		return a + b;
	}
};

这是类模板的成员函数在类内定义的情况。如果在类外定义,也需要前置一个模板声明。例如下面的实例和上面的代码是等价的:

template <typename T>
class oper
{
private:
	T a, b;

public:
	oper() {};
	oper(T, T);
	~oper() {};

public:
	bool compare()
	{
		return a > b;
	}

	T add();
};

template <typename T>
oper <T>::oper(T ia, T ib)
{
	this->a = ia;
	this->b = ib;
}

template <typename T>
T oper <T>::add()
{
	return this->a + this->b;
}

可以看到与一般的在类外定义成员函数的方法不同,这时空间解析运算符::前面的类名加了个<T>,这是模板参数,一定不能丢!!!

调用

类模板没有隐式实例化的概念,因此定义一个类模板对象时必须指定模板参数。

#include <iostream>
using namespace std;

template <typename T>
class oper
{
private:
	T a, b;

public:
	oper() {};
	oper(T ia, T ib)
	{
		this->a = ia;
		this->b = ib;
	}
	~oper() {};

public:
	bool compare()
	{
		return a > b;
	}

	T add()
	{
		return a + b;
	}
};

int main()
{
	oper <int> a(1, 5);
	cout << a.add() << ' ' << (a.compare() ? "1>5" : "1<=5") << endl;
	oper <double> b(0.75, 0.333);
	cout << b.add() << ' ' << (b.compare() ? "0.75>0.333" : "0.75<=0.333") << endl;
	//oper c('a', 'A'); error,报错:缺少类模板"oper"的参数列表
	return 0;
}

运行上面的程序,将会输出以下结果:

6 1<=5
1.083 0.75>0.333

总结/小注

模板参数列表也可以有多个,与函数参数类似地,每个参数之间用,隔开;

模板参数列表也可以有缺省参数,缺省参数规则与函数缺省参数类似,即所有的缺省参数必须放在其它参数之后

点个赞/评论支持一下吧,到现在都没人评论我。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值