学习笔记C++_7 模板

一、函数模板

1.1 template

template : 定义模板的关键字
<>:模板的参数列表
typename:定义模板类型的关键字

template<typename T>
T add(T a, T b) {
	return a + b;
}
	cout << add(10, 20) << endl;
	double a = 3.123;
	double b = 2.232;
	cout << add(a , b) << endl;

1.2 模板类型

确定模板类型:
    1.可以通过实参自动推导模板类型
    2.在调用函数时,显式的指定,模板类型
    3.在定义模板函数时,指定默认的模板类型
    显式指定 > 实参推导  > 默认类型

#include <iostream>

using namespace std;

template<typename T>
void fun() {
	T t = 0;
	cout << typeid(T).name() << " " << t << endl;
}

template<typename T=char>	//指定默认的类型
void fun2() {
	T t = 65;
	cout << typeid(T).name() << " " << t << endl;
}

template<typename T = short>
void fun3(T t) {	//实参推导模板类型
	cout << typeid(T).name() << " " << t << endl;
}

int main() {
	fun<short>();	//显示的指定模板类型
	fun2();
	fun3(1.23);
	fun3<char>(65.1);
}

1.3 模板参数

多个模板参数指定默认的类型:没有强制顺序要求
参考顺序:显式指定放于最前,实参推导放于中间,默认类型放于最后

template<typename P, typename T = short, typename Q>
void fun4(Q q) {
	cout << q << endl;
	cout << typeid(P).name() << typeid(Q).name() << typeid(T).name() << endl;
}
template<typename P,typename Q,typename T = short>
void fun5(Q q) {
	cout << q << endl;
	cout << typeid(P).name() << typeid(Q).name() << typeid(T).name() << endl;
}

	fun4<int, short, char>('A');
	fun5<int>("123");

1.4 声明及定义

1.4.1 全局函数定义?

//声明
template<typename T>
void fun6(T t);

//定义
template<typename T>
void fun6(T t) {
	cout << t << endl;
}

注意:全局函数不能给模板函数定义,在底层的函数名是不一样的

1.4.2 跨文件引用

    模板函数实例化:通用的模板函数生成具体类型的函数,在 编译期 实例化,编译期多态
    在一个编译单元内,按需实例化
    解决方法:1.模板函数声明和定义一起放在头文件中 2.显示实例化和显示具体化c++显示实例化和显示具体化_c++实例化和具体化的区别-CSDN博客

//template.h
#pragma once
template<typename T>
void fun7(T t);

template<typename T>
void fun8(T t) {
	cout << t << endl;
}
//template.cpp
#include <iostream>
using namespace std;

template<typename T>
void fun7(T t) {
	cout << t << endl;
}
void shilihua() {
	fun7(1.1);
}
//ERROR:无法解析外部符号"void fun7<>",
// 想要跨文件使用函数模板的话,需要让他显示实例化,这样子才能正常使用。
//或者将模板函数的声明和定义都写在头文件中

1.5 应用

#include <iostream>
using namespace std;

template<typename T>
bool rule_asc(T a, T b) {	//升序
	return a > b;
}
template<typename T>
bool rule_desc(T a, T b) {	//降序
	return a < b;
}

template<typename T>
void BubbleSort(T arr[], int len,bool(*p_rule)(T,T)) {
	for (int i = 0; i < len - 1; i++)
		for (int j = 0; j < len - i - 1; j++) 
			if ((*p_rule)(arr[j], arr[j+1])) {
				T temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
}

int main() {
	int arr_int[10] = { 3,4,2,6,3,5,34,3,2,4 };
	BubbleSort(arr_int, 10,rule_asc);
	for (int v : arr_int) {
		cout << v << ' ';
	}
	cout << endl;
	double arr_double[10] = { 3.4,4.7,2.2,6.9,3,5.66,34.0,3.8,2.2,4.7 };
	BubbleSort(arr_double, 10,rule_desc);
	for (double v : arr_double) {
		cout << v << ' ';
	}
	cout << endl;
}

二、类模板

2.1 类模板类型

    1.显式指定
    2.默认的模板类型

#include <iostream>
using namespace std;

template<typename T=char>
class Test {
public:
	T m_a;
	Test(const T & a):m_a(a){}
	void fun() {
		cout << typeid(T).name() << " " << m_a << endl;
	}
};

int main() {
	//显式的指定模板类型
	Test<int> tst(1);
	tst.fun();

	//默认的标准 不允许实参推导
	//Test tst(10);	//ERROR:缺少Test的参数列表

	//默认的模板类型 注意<>不可省略
	Test<> tst2('B');	
	tst2.fun();
}

2.2 类模板的默认参数列表

 类模板指定默认的类型顺序:
从右向左依次指定,中间不允许间断

template<typename T,typename K=char>
class Test {
public:
	T m_a;
	Test(const T & a):m_a(a){}
	void fun() {
		cout << typeid(T).name() << " " << m_a << endl;
	}

	template<typename M>
	void fun2(M m) {
		cout << typeid(M).name() << " " << m << endl;
		cout << typeid(T).name() << " " << m_a << endl;
		cout << typeid(K).name() << endl;
	}
};

	Test<char, double> tst('A');
	tst.fun();

2.3 类外定义

template<typename T,typename K=char>
class Test {
public:
	T m_a;
	Test(const T & a):m_a(a){}
	void fun() {
		cout << typeid(T).name() << " " << m_a << endl;
	}

	template<typename M>
	void fun3(M m);
};

//类外,类模板和函数模板同时存在,注意顺序:先类模板 再 函数模板

template<typename T, typename K>	//类模板
template<typename M>	//函数模板
void Test<T,K>::fun3(M m) {
	cout << typeid(M).name() << " " << m << endl;
	cout << typeid(T).name() << " " << m_a << endl;
	cout << typeid(K).name() << endl;
}

注意:在类外写类模板时,默认的模板类型应该删去不写

2.4 list

#include <iostream>

using namespace std;

template<typename T>

struct node {
	T data;
	node* next;
	node(const T& v) :data(v),next(nullptr){ }
};

template<typename T>
class CIterator {	//迭代器
public:
	node<T>* m_pTemp;
	CIterator(node<T>* p):m_pTemp(p){}
	bool operator!=(node<T>* p) {
		return m_pTemp != p;
	}
	T& operator *() {
		return m_pTemp->data;
	}
	node<T>* operator++() {
		m_pTemp = m_pTemp->next;
		return m_pTemp;
	}
	node<T>* operator++(int) {
		node<T>* tmp;
		tmp = m_pTemp;
		m_pTemp = m_pTemp->next;
		return tmp;
	}
};

template<typename T>
class CLinkedList {
private:
	node<T>* header;
	node<T>* ender;
	int len;
public:
	CLinkedList() {
		header = ender = nullptr;
		len = 0;
	}
	~CLinkedList() {
		node<T>* temp;
		while (header) {
			temp = header;
			header = header->next;
			delete temp;	//释放指针指向的内存
			temp = nullptr;		//指针赋空,避免非法性判断
			len--;
		}
	}
	void PushBack(const T& data) {
		node<T>* p = new node<T>(data);	//堆区
		if (len == 0)
			header = ender = p;	//指针指向节点所申请的空间
		else {
			ender->next = p;
			ender = p;
		}
		len++;
	}
	void PopFront() {
		if (header) {
			node<T>* temp = header;
			if (header == ender) {
				header = ender = nullptr;
			}
			else {
				header = header->next;
			}
			delete temp;
			temp = nullptr;
			len--;
		}
	}
	void showList() {
		CIterator<T> ite = header;
		while (ite!=nullptr) {
			cout << *ite << ' ';
			ite++;
		}
		cout << endl;
	}
	int getLen() {
		return len;
	}
};

class CTest {
public:
	int m_a;
	CTest(int v):m_a(v){}
};

ostream& operator <<(ostream& os, CTest t) {
	os << t.m_a;
	return os;
}

int main() {
	node<int> p(1);
	CLinkedList<int> list;
	list.PushBack(10);
	list.PushBack(20);
	list.PushBack(30);
	list.PushBack(40);
	list.PushBack(50);
	list.showList();
	cout << list.getLen() << endl;
	list.PopFront();
	list.showList();
	cout << list.getLen() << endl;

	CTest a1(100);
	CTest a2(200);
	CTest a3(300);
	CTest a4(400);
	CTest a5(500);
	CLinkedList<CTest> list2;
	list2.PushBack(a1);
	list2.PushBack(a2);
	list2.PushBack(a3);
	list2.PushBack(a4);
	list2.PushBack(a5);
	cout << list2.getLen() << endl;
	list2.PopFront();
	list2.showList();
}

2.5 动态数组

动态数组:动态的扩容,底层是是通过new出来的数组,存在 容量 和 使用量 的概念。

#include <iostream>
using namespace std;

template<typename T>
class DynanicArray {
public:
	T* m_pArr;
	int m_size;	//使用量
	int m_capacity;	//容量
public:
	//构造
	DynanicArray(int size = 0) :m_pArr(size > 0 ? m_pArr = new T[size]() : nullptr), m_size(0), m_capacity(size) {}
	//拷贝
	DynanicArray(const DynanicArray& arr) :m_size(arr.m_size), m_capacity(arr.m_capacity) {
		if (arr.m_pArr) {
			m_pArr = new T[m_capacity]();
			for (int i = 0; i < m_size; i++) {
				m_pArr[i] = arr.m_pArr[i];
			}
		}
		else m_pArr = nullptr;
	}
	void PushBack(const T& v) {
		if (m_size < m_capacity) {	//数组未满
			m_pArr[m_size++] = v;
		}
		else {	//扩容,默认将其扩大1.5倍
			m_capacity = max(m_capacity * 3 / 2, m_capacity + 1);
			T* pTemp = new T[m_capacity]();	//申请新的大空间
			for (int i = 0; i < m_size; i++) {	//拷贝
				pTemp[i] = m_pArr[i];
			}
			pTemp[m_size++] = v;

			delete[] m_pArr;
			m_pArr = pTemp;
		}
	}
	void PopBack() {
		if (m_size > 0) {
			m_size--;
		}
	}
	void show() {
		for (int i = 0; i < m_size; i++) {
			cout << m_pArr[i] << ' ';
		}
		cout << endl;
	}
	//左闭右开区间
	T* begin() {
		return m_pArr;
	}
	T* end() {
		return &m_pArr[m_size];
	}
};

int main() {
	DynanicArray<int> arr;
	arr.PushBack(1);
	cout << arr.m_size << ' ' << arr.m_capacity << endl;
	arr.PushBack(2);
	cout << arr.m_size << ' ' << arr.m_capacity << endl;
	arr.PushBack(3);
	cout << arr.m_size << ' ' << arr.m_capacity << endl;
	arr.PushBack(4);
	cout << arr.m_size << ' ' << arr.m_capacity << endl;
	arr.PushBack(5);
	cout << arr.m_size << ' ' << arr.m_capacity << endl;
	arr.PushBack(6);
	cout << arr.m_size << ' ' << arr.m_capacity << endl;
	arr.PushBack(7);
	cout << arr.m_size << ' ' << arr.m_capacity << endl;
	arr.show();
	arr.PopBack();
	arr.PopBack();
	arr.show();
	cout << arr.m_size << ' ' << arr.m_capacity << endl;
	DynanicArray<int> arr2(arr);
	arr2.PushBack(8);
	cout << arr2.m_size << ' ' << arr2.m_capacity << endl;
	arr2.show();
	for (int v : arr2) {
		cout << v << ' ';
	}
	cout << endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值