【C++】模板(定义和使用)

泛型编程

泛型编程是一种很高级的编程思路,感性来理解的话,泛型编程思想编出来的代码往往需要有两个功能:

所有类型的数据都可以处理
所有数据结构所管理的数据都可以处理
总结来说就是不区分数据类型和数据结构

函数模板

针对加法函数,我们可以会这样定义

int Add(int left, int right)
{
	return left + right;
}

但是我们需要传递的参数如果不是两个整型那就不行了。如果需要传递的参数是double,需要重新进行函数的重载

double Add(double left, double right)
{
	return left + right;
}

但是如果传递的参数再发生变化,那么就又需要重新定义了,这样就非常麻烦,我们也不可能把所有的类型都定义出来。
这时候就需要用到函数模板了
函数模板的思路是这样的:我们以往的思路是调用函数时传递参数,事先定义好函数。那么我们可不可以抽象出一种函数,它无关于参数类型,只负责实现我们需要的功能,这样我们不就可以实现任意类型了吗?
函数模板就是这样做的,它定义了一种模板,只告诉编译器需要实现什么功能,而传递的参数类型只有在真正调用时才由编译器自行判断,自行生成函数。
我们举这样一个例子,实现两个参数的交换

template<typename T>
void Swap( T& left, T& right)
{
 	T temp = left;
 	left = right;
 	right = temp;
}

可以看到,我们并没有定义出传递的参数是什么类型,而是用T这样一个标志,通过template这样一个关键字定义。
在编译器编译阶段,编译器根据传入的实参类型来推演生成对应类型的函数以供调用。针对上述函数模板,当我们用int类型使用函数模板时,编译器通过对实参类型的推演,发现T需要被定义为int类型,然后会生成一份专门处理int类型的代码。

函数模板的实例化

对于类,通过类创建一个实体的过程叫做实例化,对于函数模板也一样,通过函数模板创建出一个函数的过程也叫做实例化。

函数模板的实例化分为两种类型:显式实例化和隐式实例化。

显式实例化Add<int>(1, 2)就是告诉编译器:我需要将当前这个函数模板实例化出的函数是什么类型。
隐式实例化Add(1, 2)就是不告诉编译器,让编译器通过传递的实参自行判断。

而针对隐式实例化,如果我们传递的参数类型和函数模板不匹配,那么编译器会报错。

显式实例化不同,如果传递的参数类型和函数模板不匹配,那么编译器会进行类型转换,只有当无法类型转换时,编译器才会报错。

另外需要注意的是:

当函数和函数模板同名时,如果传递的参数类型和函数完全一致,那么就之间调用当前的函数,而不会进行函数模板的实例化。如果传递的参数和当前存在的函数参数类型不一致,那么就会调用函数模板,来实例化出更加符合当前参数类型的函数。

函数模板的编译原理

编译原理分为两步:

第一步:在函数模板实例化前对函数模板本身的代码进行简单的语法检测(例如看书写的格式是否是一个函数模板格式,甚至在早先的VS编译器中,都不会检测函数模板内部的语法)
第二步:在实例化后,编译器会根据实例化情况结合模板代码生成处理具体类型的代码

类模板

与函数模板类似,类模板也是创建出一种模板来,为了实现在通过这个类模板创建出和类型无关的类,从而提高代码的复用率。

例如:在数据结构中需要实现一个顺序表,顺序表的类定义如下

template<class T>
class vector
{
public:
	vector(size_t capacity = 3)
	{
		_capacity = capacity <= 3 ? 3 : capacity;
		_array = new T[_capacity];
		_size = 0;
	}

	~vector()
	{
		if (_array)
		{
			delete[] _array;
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}

	void push_back(const T& data)
	{
		if(_size == _capacity)
			reserve(_capacity*2);

		_array[_size] = data;
		++_size;
	}

	void pop_back()
	{
		if (empty())
			return;

		--_size;
	}

	bool empty()const
	{
		return 0 == _size;
	}

	size_t size()const
	{
		return _size;
	}

	size_t capacity()const
	{
		return _capacity;
	}

	// []: 下标运算符
	T& operator[](size_t index);
	const T& operator[](size_t index)const;

	void reserve(size_t newcapacity)
	{
		//...
	}
private:
	T* _array;
	size_t _size;
	size_t _capacity;
};

template<class T>
T& vector<T>::operator[](size_t index)
{
	assert(index < _size);
	return _array[index];
}

template<class T>
const T& vector<T>::operator[](size_t index)const
{
	assert(index < _size);
	return _array[index];
}

void TestSeqList()
{
	// vector s1(10);  // 编译失败,因为SeqList不是具体的类,是生成类的模具
	vector<int> s1(10);
	s1.push_back(1);
	s1.push_back(2);
	s1.push_back(3);
	s1.push_back(4);


	cout << s1[0] << endl;
	s1[0] = 100;

	vector<string> s2(10);
	s2.push_back("hello");
	s2.push_back("world");
	s2.push_back("bites");
	s2.push_back("!!!");
}


// 将Stack的代码用模板来封装 || 将堆的代码用模板来封装
int main()
{
	TestSeqList();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++模板类是一种通用的类,它允许您定义一种可以适用于多种数据类型的类。模板定义的语法如下: ``` template <class T> class ClassName { // class definition }; ``` 其中,`T` 是一个占位符,它可以被实际的数据类型替换。例如,如果您想要创建一个可以用于存储整数或浮点数的类,您可以这样定义: ``` template <class T> class MyArray { public: MyArray(int size); T& operator[](int index); private: T* data; int size; }; template <class T> MyArray<T>::MyArray(int size) { data = new T[size]; this->size = size; } template <class T> T& MyArray<T>::operator[](int index) { return data[index]; } ``` 在上面的代码中,`MyArray` 是一个模板类,`T` 是一个占位符,可以被实际的数据类型替换。在类定义中,我们使用了 `T` 来声明成员变量 `data` 和 `size`,以及成员函数 `MyArray` 和 `operator[]`。 要使用模板类,您需要在创建类对象时指定实际的数据类型。例如,要创建一个 `MyArray` 对象来存储整数,可以这样写: ``` MyArray<int> arr(10); ``` 在上面的代码中,`<int>` 告诉编译器使用 `int` 数据类型替换 `T`。这将创建一个可以存储 10 个整数的 `MyArray` 对象。要访问数组元素,可以使用下标运算符 `[]`,如下所示: ``` arr[0] = 5; int x = arr[0]; ``` 在上面的代码中,`arr[0] = 5` 将整数 5 存储在数组的第一个元素中,`int x = arr[0]` 将数组的第一个元素赋值给变量 `x`。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值