函数模板与类模板

泛型(Generic Programming)即是指具有在多种数据类型上皆可操作的含意。泛型编程的代表作品 STL 是一种高效、泛型、可交互操作的软件组件。
泛型编程初诞生于C++中,目的是为了实现C++的STL(标准模板库)。 其语言支持机制就是模板(Templates)
模板的精神其实很简单:参数化类型。 换句话说,  把一个原本特定于某个类型的算法或类当中的类型信息抽掉,抽出来 做成模板参数 T

所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板
在这里插入图片描述

函数模板

在这里插入图片描述
template 是语义是模板的意思,尖括号中先写关键字 typename 或是 class ,后面跟一个类型 T,此类即是虚拟的类型。至于为什么用 T,用的人多了,也就是 T 了。 

调用过程是这样的,先将函数模板实在化为函数,然后再发生函数调用
在这里插入图片描述
函数模板,只适用于函数的参数个数相同 而 类型不同 ,且 函数体相同的情况。 如果个数不同,则不能用函数模板。

普通函数会进行隐士的数据类型转换, 
函数模板不提供隐式的数据类型转换, 必须是严格的匹配。 
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
函数模板可以像普通函数那样都可以被重载

编译器对模板机制剖析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

类模板

类模板与函数模板的定义和使用类似,我们已经进行了介绍。有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,所以将类中的类型进行泛化。 
在这里插入图片描述

在这里插入图片描述

模板类的派生

在这里插入图片描述

类模板实现

函数体写在类中
在这里插入图片描述
在这里插入图片描述
函数体写在类外
在这里插入图片描述
使用这个类模板,需要前面要加上面红框内的,声明,所以不要滥用友元,非常麻烦
friend Complex< T > mySub < T > (Complex< T > &one,Complex< T> &another)
在这里插入图片描述
在这里插入图片描述
综上: 模板类不要轻易使用友元函数。

类模板中的static

在这里插入图片描述

例子:实现一个模板数组类

#include<iostream>
using namespace std;

template<class T>
class MyArray{
public:
	MyArray<T> (int capacity){
		this->mCapacity = capacity;
		this->mSize = 0;
		//申请内存
		this->pAddr = new T[this->mCapacity];
	}
	MyArray<T> (const MyArray<T>& arr){
		this->mSize = arr.mSize;
		this->mCapacity = arr.mCapacity;

		//申请内存空间
		this->pAddr = new T[this->mCapacity];
		//数据拷贝
		for (int i = 0; i < this->mSize; i++){
			this->pAddr[i] = arr.pAddr[i];
		}

	}
	T& operator[](int index){
		return this->pAddr[index];
	}

	MyArray<T>& operator=(const MyArray<T>& arr){

		if (this->pAddr != NULL){
			delete[] this->pAddr;
		}

		this->mSize = arr.mSize;
		this->mCapacity = arr.mCapacity;

		//申请内存空间
		this->pAddr = new T[this->mCapacity];
		//数据拷贝
		for (int i = 0; i < this->mSize; i++){
			this->pAddr[i] = arr.pAddr[i];
		}

		return *this;
	}
	
	void PushBack(T& data){
		//判断容器中是否有位置
		if (this->mSize >= this->mCapacity){
			return;
		}
		
		//调用拷贝构造 =号操作符
		//1. 对象元素必须能够被拷贝
		//2. 容器都是值寓意,而非引用寓意 向容器中放入元素,都是放入的元素的拷贝份
		//3  如果元素的成员有指针,注意深拷贝和浅拷贝问题
		this->pAddr[this->mSize] = data;
		//msize++
		this->mSize++;
	}
	
	//右值引用  类型 &&a =右值表达式
	//T&& 对右值取引用
	void PushBack(T&& data){
		//判断容器中是否有位置
		if (this->mSize >= this->mCapacity){
			return;
		}

		this->pAddr[this->mSize] = data;
		//msize++
		this->mSize++;
	}

	~MyArray(){
		if (this->pAddr != NULL){
			delete[] this->pAddr;
		}
	}
public:
	//一共可以容下多少个元素
	int mCapacity;
	//当前数组有多少元素
	int mSize;
	//保存数据的首地址
	T* pAddr;
};

void test01(){

	MyArray<int> marray(20);
	int a = 10, b = 20, c = 30, d = 40;
	marray.PushBack(a);
	marray.PushBack(b);
	marray.PushBack(c);
	marray.PushBack(d);

	//不能对右值取引用
	//左值 可以在多行使用
	//右值 临时变量 只能当前行使用
	marray.PushBack(100);
	marray.PushBack(200);
	marray.PushBack(300);

	for (int i = 0; i < marray.mSize; i++){
		cout << marray[i] << " ";
	}
	cout << endl;
}

class Person {
	friend ostream& operator<<(ostream& os, Person& person) {
		os << "Age:" << person.mAge << " " << "Id:" << person.mId << endl;
		return os;
	}
public:
	Person() {
		this->mAge = 0;
		this->mId = 0;
	}
	Person(int age,int id) {
		this->mAge = age;
		this->mId = id;
	}
public:
	int mAge;
	int mId;
};

void test02(){

	Person p1(10,20), p2(30,40);

	MyArray<Person> arr(10);
	arr.PushBack(p1);
	arr.PushBack(p2);

	for (int i = 0; i < arr.mSize; i++) {
		cout << arr[i];
	}
	cout << endl;

}


int main(){
	//test01();
	test02();

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值