文章目录
1. 函数模板
1.1 函数模板特点
(1)函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,简化重载函数的设计。函数模板定义如下:template<模板参数表>返回类型函数名(形式参数表) {.....; }//函数体
(2)<模板参数表>(template parameter list)尖括号中不能为空,参数可以有多个,用逗号分开。
模板参数主要是模板类型参数。
(3)模板类型参数(template type parameter)代表一种类型,由关键字class或typename(建议用typename )后加一个标识符构成,在这里两个关键字的意义相同,它们表示后面的参数名代表一个潜在的内置或用户定义的类型。
(4)函数模板根据一组实际类型或(和)值构造出独立的函数的过程通常是隐式发生的,称为模板实参推演(templateargument deduction)。
(5)为了判断用作模板实参的实际类型,编译器需检查函数调用中提供的函数实参的类型。ia 的类型为int数组,dx的类型为double 数组。都被用来决定每个实例的模板参数。该过程称为模板实参推演。
1.2 代码示例
1.2.1 例1:类型推演
代码示例
#include<iostream
#include<typeinfo>
using namespace std;
template<class T>
void fun(T a)
{
T x, y;
cout << "T type:" << typeid(T).name() << endl;
cout << "a type:" << typeid(a).name() << endl;
}
int main()
{
//int x = 10;//int int*
//const int x=10;//int const int*
/*fun(x);
fun(&x);*/
/*
int x=10;
const int y=10;
int*xp=&x;
const int*yp=&y;
fun(xp);
fun(yp);
//int* const int* */
}
运行结果
1.2.2 例2:类型推演失败
因为明确给出需要指针类型,给出的是整型,类型不匹配,推演失败,函数都可以重载
using namespace std;
template<class T>
void fun(T* a)//必须是指针所有推演失败 部分泛化
{
T x, y;
cout << "T type: " << typeid(T).name() << endl;
cout << "a type: " << typeid(a).name() << endl;
}
int main()
{
int x = 10;
const int y = 10;
fun(x);
fun(y);
//推演失败解决办法:加引用
fun(&x);//int int*
fun(&y);//int const int*
return 0;
}
1.2.3 例3:类型推演
template<class T>
void fun(T& a)
{
T x, y;
cout << "T type: " << typeid(T).name() << endl;
cout << "a type: " << typeid(a).name() << endl;
}
int main()
{
int x = 10;
const int y = 10;
int* xp = &x;
const int* yp = &y;
fun(x);
fun(y);
fun(&x);
fun(&y);
fun(xp);
fun(yp);
return 0;
}
2. 模板函数
2.1 定义
在编译main()函数中,由编译函数模板(functron template)而生成的函数,称为模板函数(template function).这两个概念须分清楚。
2.2 泛化
void fun(T a)//完全泛型
void fun(T *a);//部分泛型
void fun<char>(const char* a)//完全特化
2.3 模板类型推演示例
2.3.1 类型推演示例
template<class T>
void fun(T a)
{
T x, y;
cout << "T type: " << typeid(T).name() << endl;
cout << "a type: " << typeid(a).name() << endl;
}
int main()
{
int x = 10;
const int y = 20;
int* xp = &x;
const int* yp = &y;
fun(x);//int int
fun(y);//int int
fun(&x);//int* int*
fun(&y);//const int* const int*
fun(xp);//int* int*
fun(yp);//const int* const int*
fun(&xp);//int** int**
fun(&yp);//const int** const int**
}
2.3.2 推演失败案例,类型不匹配
template<typename T>
void fun(T* a)
{
T x, y;
cout << typeid(T).name() << endl;
cout << typeid(a).name() << endl;
}
int main()
{
int x = 10;
const int y = 20;
fun(x);//推演失败(类型不匹配)
fun(y);//推演失败
return 0;
}
2.3.3 无类型指针示例
代码示例
template<typename T>
void fun(T* a)
{
T x, y;
cout << typeid(T).name() << endl;
cout << typeid(a).name() << endl;
}
int main()
{
int x = 10;
const int y = 20;
int* xp = &x;
const int* yp = &y;
void* p = &x;//无类型指针
//带有类型萃取能力
fun(&x);//int int*
fun(&y);//const int const int*
fun(p);//void void*
return 0;
}
无类型无法定义变量
2.4.模板函数的引用
代码示例
template<typename T>
void fun(T& a)//引用是和变量名结合,不是和类型名结合
{
T x = 0, y = 0;//进行初始化才能编译通过
cout << typeid(T).name() << endl;
cout << typeid(a).name() << endl;
}
int main()
{
int x = 10;
const int y = 20;
fun(x);//int int&
fun(y);//const int const int&
return 0;
}
运行结果
2.5 引用与指针结合
代码示例
template<typename T>
void fun(T& a)//引用是和变量名结合,不是和类型名结合
{
T x = 0, y = 0;//进行初始化才能编译通过
cout << typeid(T).name() << endl;
cout << typeid(a).name() << endl;
}
int main()
{
int x = 10;
const int y = 20;
int* xp = &x;
const int* yp = &y;
fun(xp);//int* int*&
fun(yp);//const int* const int*&
return 0;
}
运行结果
2.6 引用与二级指针结合
template<typename T>
void fun(T const& a)//引用是和变量名结合,不是和类型名结合
{
T x = 0, y = 0;//进行初始化才能编译通过
cout << typeid(T).name() << endl;
cout << typeid(a).name() << endl;
}
int main()
{
int x = 10;
const int y = 20;
fun(&x);//int* int const*
fun(&y);//int* int const*
return 0;
}
2.7 模板函数类型推演示例
代码示例
template<class T>
void fun(T a)
{
cout << "T a" << endl;
}
template<class T>
void fun(T* a)
{
cout << "T *a" << endl;
}
template<class T>
void fun(const T* a)
{
cout << "const T*" << endl;
}
int main()
{
int x = 10;
const int y = 20;
fun(x);//T
fun(&x);//T*
fun(&y);//const T*
}
运行结果
2.8 模板函数的重载
template<class T>
void fun(T a, int)
{
}
template<class T>
void fun(T a, char)
{
}
int main()
{
fun(12, 23);
fun(12, 'a');
return 0;
}
3. 类模板
3.1 概念
(1)类模板不存在推演过程
(2)类模板中的函数都是模板函数
代码示例
void push(const T& x)
{
cout<<N<<endl;
N=100;
}
3.2 代码示例
//类模板
template<class T>
class stack
{
T* data;
size_t count;
public:
void Push(const T& x);
};
3.3 模板函数类型
template<class T,int N>
class Stack
{
T data[N];
public:
void push(const T& x);
};
int main()
{
//is和ist类型不相同
Stack<int, 100> is;
Stack<int, 10> ist;
return 0;
}
3.4 模板函数中的new
template<class T>
class Array
{
enum { INIT = 10 };
T* data;//.heap 10
size_t capacity;//10
size_t count;//5
public:
Array()
{
count = 0;
data = new T[capacity = INIT];//连续开辟数组,调动构造函数,对每个空间构造函数
}
~Array() { delete[]data; }
};
int main()
{
Array<int> ar;
Array<double> dr;
}
3.5 模板类型识别
int main()
{
Array<int> a;//不是模板类型,已经被实例化
Array b;
}
3.6 综合代码示例
#define _CRT_SECURE_NO_WARNINGS
#include"stdio.h"
#include<iostream>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<vector>
#include<map>
#include<list>
#include<thread>
#include<mutex>
#include<typeinfo>
#include<map>
#include<queue>
#include<functional>
using namespace std;
class String
{
protected:
struct StrNode
{
int ref; // 引用计数
int len; // 字符串的长度
int size; // 柔性数组的容量
char data[];
};
private:
StrNode* pstr;
public:
String(const char* p = NULL) :pstr(NULL)
{
if (p != NULL)
{
int sz = strlen(p);
pstr = (StrNode*)malloc(sizeof(StrNode) + sz * 2 + 1);
pstr->ref = 1;
pstr->len = sz;
pstr->size = sz * 2;
strcpy(pstr->data, p);
}
}
~String()
{
if (pstr != NULL && --pstr->ref == 0)
{
free(pstr);
}
pstr = NULL;
}
String(const String& str) :pstr(NULL)
{
if (str.pstr != NULL)
{
pstr = str.pstr;
pstr->ref += 1;
}
}
String& operator=(const String& s)
{
if (this == &s) return *this;
if (this->pstr != NULL && --this->pstr->ref == 0)
{
free(this->pstr);
}
this->pstr = s.pstr;
if (this->pstr != NULL)
{
this->pstr->ref += 1;
}
return *this;
}
char& operator[](const int index)
{
//写时拷贝
if (pstr == NULL) exit(1);
assert(index >= 0 && index <= pstr->len - 1);
//越界问题
if (pstr->ref > 1)
{
int total = sizeof(StrNode) + pstr->size + 1;
StrNode* newnode = (StrNode*)malloc(total);
memmove(newnode, pstr, total);
newnode->ref = 1;
pstr->ref -= 1;
pstr = newnode;
}
return pstr->data[index];
}
const char& operator[](const int index) const
{
return (*this)[index];
}
ostream& operator<<(ostream& out) const
{
if (pstr != NULL)
{
out << pstr->data;
}
return out;
}
String(String&& s);//移动构造
String& operator=(String&& s);//移动赋值
};
ostream& operator<<(ostream& out, const String& s)
{
s << out;
return out;
}
int main()
{
String s1("yhping");
String s2(s1);
String s3("hello");
String s4("new");
//s1 = s1 + s4;
}