模板
函数模板
- 一个通用函数,函数类型和参数类型不具体指定
- 函数模板把要处理的数据类型参数化,表现为参数的多态性
- 模板关键字 template 类型关键字 typename
- 函数模板使用的两种方式:
- 显示指定类型函数名 例:add(10, 20)
- 直接传值,靠类型推导 例: add(10, 0.1)
template<typename T,typename M>
M add(T t, M m) {
return t + m;
}
template<typename T>
void tSwap(T& t1, T& t2) {
T temp = t1;
t1 = t2;
t2 = temp;
}
int main(){
int in1 = 10;
double in2 = 20;
cout<<in1<<","<<in2<<endl;
double c = add(in1, in2);
cout<<"in1 + in2 = "<<c<<endl;
tSwap(c, in2);
cout<<c<<","<<in2<<endl;
return 0;
}
- 模板函数不会自动进行类型转换,普通函数会自动进行类型转换
- 如果同时匹配普通函数和模板函数,优先考虑普通函数
void fun(int n1, int n2) {
cout<<"normal函数被调用"<<endl;
}
template<typename T>
void fun(T n1, T n2) {
cout<<"template 函数被调用"<<endl;
}
int main() {
fun(1, 'a');// 普通函数被调用
fun(1, 1); // 普通函数被调用
return 0;
}
函数模板的重载
class Person {
public:
int age;
Person(int age):age(age){}
};
template<typename T>
int compare(T n1, T n2) {
if (n1 > n2) return 1;
else if (n1 < n2) return -1;
else return 0;
}
template<>
int compare<Person>(Person& p1, Person& p2) {
if (p1.age < p2.age) return -1;
else if (p1.age > p2.age) return 1;
else return 0;
}
int main(){
Person p1 = {19};
Person p2 = {30};
cout<< compare(p1, p2)<< endl;
return 0;
}
练习
- 定义一个函数 将数组元素拼接为一个字符串 返回
#include<sstream>
using namespace std;
template<typename T>
string toString(T* arr, int len) {
if (len == 0) return "[]";
ostringstream oss;
oss<<"[";
for (int i = 0; i < len - 1; i++) {
oss<<arr[i]<<",";
}
oss<<arr[len - 1]<<"]";
return oss.str();
}
int main(){
int arr[10];
cout<<sizeof(arr)/ sizeof(int)<<endl;
for (int i = 0; i < 10; i++) {
arr[i] = i;
}
cout<<toString(arr, 10)<<endl;
return 0;
}
- 定义一个函数模板 实现将一个数组中的元素升序排序返回
template<typename T>
void mySort(T* arr, int len) {
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len; j++) {
if (arr[i] < arr[j]) continue;
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
}
int main(){
default_random_engine e;
int arr[10];
cout<<sizeof(arr)/ sizeof(int)<<endl;
for (int i = 0; i < 10; i++) {
arr[i] = e() * 1000 % 69;
}
for (int in : arr) cout<< in <<",";
cout<<endl;
mySort(arr, 10);
for (int in : arr) cout<< in <<",";
return 0;
}
类模板
- 类模板不能自动类型转换,使用时必须声明使用类型
template<typename T>
class Numbercalculator {
private:
T n1;
T n2;
public:
Numbercalculator(T n1, T n2): n1(n1), n2(n2){}
void showAddResult() {
cout<<n1 + n2 <<endl;
}
};
int main(){
Numbercalculator<int> numC = {1, 3};// 使用时必须声明类型
numC.showAddResult();
return 0;
}
vector容器的构造
// vector 的构造
vector<int> v;
vector<int> v1(10,1);// 容器里有10个1
vector<int> v2 = v1;
vector<int> v3(v2.begin(), v2.end());// 或 vector(v2.begin(), v2.begin() + 5)
int arr[5] = {1,2,3, 4,1};
vector<int> v4(arr, arr + 3);
vector的常用方法 | ||
---|---|---|
size | 大小 | |
capacity | 容量 |
使用swap对容器“瘦身”
vector<int>(v).swap(v);// 创建一个匿名对象,此时,匿名对象的容量大小都是原容器的元素个数,然后,再把原容器和匿名对象交换,原来的容器的容量和大小就变成大小了。
deque容器
和vector区别在于,vector是单向开口容器,deque是双向开口容器。vector内存不足时会重新开辟一块连续的空间,然后把原来的数据复制进去,deque是用引用分别指向不同空间,每个空间代表一个元素,如果要插入元素,只需要新增引用,在开辟一块空间。
stack
queue队列
list链表
set
- 底层用二叉树实现,只能遍历不能修改。
- 和multiset区别在于,不允许重复。
- 不能用索引得到。
|常用方法||
|—|—|
|lower_bound(int n)|返回第一个小于等于查找值的元素|
|upper_bound(int n)|返回第一个大于等于查找值的元素|
pair
- 两个数据的整合
pair<string, int> p("小明", 18);
cout<<p.first<<","<<p.second<<endl;
pair<int, int> p = make_pair(12, 10);
cout<<p.first<<","<<p.second<<endl;
map
// 构造
map<string, int> m;
// 插入
m.insert(pair<string, int>("小明", 18));
m.insert(map<string, int>::value_type("history", 20));
m.insert(make_pair("小红", 40));
m["hhh"] = 666;
// m.earse() 删除某个元素
for (auto it = m.begin(); it != m.end(); it++) {
cout<<(it->first)<<","<< (it->second)<<endl;
}
/*
// 打印结果
hhh,666
history,20
小红,40
小明,18
*/