一、函数模板
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;
}