C++(模版)

1.泛型编程

泛型编程是一种编程范式,允许编写与类型无关的代码。通过使用泛型,可以编写可以与多种数据类型一起使用的代码,增加代码的重用性和灵活性。例如,在编写一个排序算法时,泛型使得同一个排序函数可以处理整数、浮点数或自定义对象等不同类型的数据。

/* 实现数值交换 */
void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}

void Swap(double& left, double& right)
{
	int temp = left;
	left = right;
	right = temp;
}

void Swap(char& left, char& right)
{
	int temp = left;
	left = right;
	right = temp;
}
/* 
	虽然我们可以使用函数重载实现
	但是代码利用率低,只要有新的类型出现
	用户就必须手动实现,增加对应的函数
	代码维护性较低,一个出错很可能其他重载都会出错
*/
//......

2.函数模版

函数模版代表了一个函数家族,该函数模版与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

格式 :template<typename T1, typename T2,......,typename Tn>

返回值类型 函数名(参数列表){}

/* typename是用来定义模版参数关键字,也可以使用class(不可使用struct) */
template <typename T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
	std::cout << "left[" << left << "]right[" << right << "]" << std::endl;
}


int main()
{
	int left = 0, right = 10;
	/*
		使用方法1 函数名<类型>(参数)
		2:可直接按照调动普通函数的方式调用
	*/
	Swap<int>(left, right);
	Swap(left, right);
	return 0;
}

函数模版不是函数,是编译器使用方法产生特定具有类型函数的模具

在编译器编译阶段,对于模版函数的,编译器会根据传入的实参类型进行类型推演,生成对应的类型以供调用。

函数模版的实例化

用不同类型的参数使用函数模版时,成为函数模版的实例化。

模版参数实例化(隐式实例化和显示实例化)

/* typename是用来定义模版参数关键字,也可以使用class(不可使用struct) */
template <typename T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

int main()
{
	/*
		隐式类型实例化
	*/
    int left = 0, right = 10;
    Swap(left, right);
    double left1 = 2.1;
    double right1 = 10.3;
    Swap(left1, right1);

	/* 
		错误写法:Swap(left, right1)
		此时编译器看到此实例化时,进行类型推演
		left推演出来的是int
		right1推演出来的是double
		但是参数模版中只有一个T
		此时隐式调用编译器无法确定该T为什么类型
		注:编译器一般不进行类型转换操作

		此时我们应该选用显示类型实例化
	*/

	/* 显示类型实例化 */
	char left2 = 2, right2 = 2;
	Swap<char>(left2, right2);

    return 0;
}	

注:隐式类型实例化,类型不匹配,则无法转换成功,编译器将报错

模版参数调用匹配原则

/* 
	当非模版函数和函数模版同名且同时存在时,
	函数模版依旧可以实例化为该类型
*/
void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
	std::cout << "void Swap(int& left, int& right)" << std::endl;
}

template <typename T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
	std::cout << "void Swap(T& left, T& right)" << std::endl;
}

int main()
{
	int Ileft = 10, Iright = 20;
	/* 与非模版函数匹配, 编译器不需要特化 */
	Swap(Ileft, Iright);

	/* 编译器需要特化为Swap版本 */
	Swap<int>(Ileft, Iright);

	return 0;
}

int ADD(int left, int right)
{
	std::cout << "int ADD(int& left, int& right)" << std::endl;
	return left + right;
}

template <typename T1, typename T2>
int ADD(T1 left, T2 right)
{
	std::cout << "int ADD(T1& left, T2& right)" << std::endl;
	return left + right;
}


int main()
{
	/* 
		对于隐式类型实例化
		非模版函数和同名函数模版,
		如果其他条件相同,编译器优先调用非模版函数
		如果模版可以产生一个具有更好的匹配函数,则使用模版
	*/
	ADD(1, 2);/* 与非模版函数匹配 */
	ADD(1, 2.0);/* 模版函数可以产生更好的匹配函数 */

}

注: 模版函数不允许自动类型转换, 但普通函数可以进行自动类型转换

3.类模版

类模版的格式定义

template <typename T, typename U ......>
class ClassName {
    // 类定义
};
/* 
* #define type int
	之前使用define定义存储类型
	无法在一个类中,存储不同类型
	注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
*/
template <class T>
class Vector 
{
public:
	Vector(size_t capacity = 10)
		: _pData(new T[capacity])
		, _size(0)
		, _capacity(capacity)
	{}

	~Vector();

	void PushBack(const T& data);
		void PopBack();
		// ...

		size_t Size() { return _size; }

	T& operator[](size_t pos)
private:
	T* _pDate;
	size_t _size;
	size_t _capacity;
};

/* 注:类模板中函数放在类外进行定义时,需要加模板参数列表 */
template <class T>
Vector<T>::~Vector()
{
	if (_pData)
		delete[] _pData;
	_size = _capacity = 0;
}

类模版的实例化与函数模版实例化不同,类模版实例化需要再类模版后面跟<>, 将需要实例化的类型放入<>中

注: 类模版类名不是真正的类, 而实例化后的结果才是类。

	/* Vector类名 Vector<int>才是类型 */

	Vector<int> s1;
	Vector<double> s1;

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值