嵌入式学习-C嘎嘎-Day04
1. 模(mú)板
1.1 函数模板
1.2 类模板
2. 容器
2.1 相关概念
2.2 容器分类
2.2.1 顺序容器
2.2.1.1 array 数组
2.2.1.2 vector 向量
2.2.1.3 list 列表
2.2.1.4 deque 队列
2.2.2 关联容器
2.3 迭代器 iterator
1. 模(mú)板
模板可以让程序员编写与类型无关的代码,模板可以让类或函数声明一种通用类型,在使用的过程中一些变量、参数或返回值可以是任意类型。
模板通常有两种实现方式:
- 函数模板
- 类模板
模板是一种参数化多态的工具。
1.1 函数模板
编写函数模板时,需要确定函数算法的适用性。
#include <iostream>
using namespace std;
// 模板声明
template <class T>
T add(T a,T b)
{
return a+b;
}
class Dog
{
};
int main() {
cout << add(2,3) << endl; // 5
cout << add(2.2,3.3) << endl; // 5.5
cout << add('A','A') << endl; // ?
string a = "abc";
string b = "123";
cout << add(a,b) << endl;
Dog d1;
Dog d2;
// add(d1,d2); 参数可以正常传入
return 0;
}
1.2 类模板
#include <iostream>
using namespace std;
template <typename T>
class Test
{
private:
T value;
public:
Test(T v):value(v){}
T get_value() const
{
return value;
}
void set_value(T value)
{
this->value = value;
}
};
int main()
{
Test<int> t1(1);
cout << t1.get_value() << endl;
Test<double> t2(1.1);
cout << t2.get_value() << endl;
return 0;
}
把上面的写法改为类内声明,类外定义的方式
#include <iostream>
using namespace std;
template <typename T>
class Test
{
private:
T value;
public:
Test(T v);
T get_value() const;
void set_value(T value);
};
template<class T>
Test<T>::Test(T v):value(v){} // 构造函数
template<class T>
T Test<T>::get_value() const // getter
{
return value;
}
template<class T>
void Test<T>::set_value(T value) // setter
{
this->value = value;
}
int main()
{
Test<int> t1(1);
cout << t1.get_value() << endl;
Test<double> t2(1.1);
cout << t2.get_value() << endl;
return 0;
}
2. 容器
2.1 相关概念
泛型编程(Generic Programming)最初提出时的动机很简单直接:发明一种语言机制,能够帮助实现一个通用的标准容器库。所谓通用的标准容器库,就是要能够做到,比如用一个List类存放所有可能类型的对象这样的事;泛型编程让你编写完全一般化并可重复使用的算法,其效率与针对某特定数据类型而设计的算法相同。
标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。虽说它主要表出现到C++中,但在被引入C++之前该技术就已经存在了很长时间。
STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
2.2 容器分类
容器类型在使用时均需要引入对应的头文件,并且容器对象本身只能在栈内存。
思维导图插件
2.2.1 顺序容器
顺序容器是一种线性结构的可续群集,各个元素之间按照先后顺序排列,可以使用删除或插入操作改变顺序(array例外)。
2.2.1.1 array 数组
array是C++11中新增的数据类型,相比于传统的内置数组更加安全且更容易使用。
#include <iostream>
#include <array> // 数组
using namespace std;
int main()
{
// 创建一个长度为3的int数组
array<int,3> arr;
cout << arr.size() << endl; // 3
// 赋值
arr[1] = 2;
// 取出元素
cout << arr[0] << endl; // 输出结果不定
cout << arr.at(1) << endl; // 更安全
// 填充
arr.fill(10086);
// for循环遍历
for(int i = 0;i<arr.size();i++)
{
cout << arr.at(i) << " ";
}
cout << endl;
// for-each遍历
for(int i:arr)
cout << i << " ";
cout << endl;
// 迭代器遍历:(略)
return 0;
}
2.2.1.2 vector 向量
vector内部由数组实现,元素的内存地址是连续的,因此可以高效地进行随机存取,但是不擅长插入删除。
#include <iostream>
#include <vector> // 向量
using namespace std;
int main()
{
vector<int> vec1; // 创建一个长度为0的int向量
cout << vec1.empty() << endl; // 判断是否为空
vector<int> vec2(vec1); // 拷贝构造函数
cout << vec2.size() << endl; // 0
vector<int> vec3(5); // 5个0
// for循环遍历
for(int i=0;i<vec3.size();i++)
{
cout << vec3.at(i) << " ";
}
cout << endl;
vector<int> vec4(5,2); // 5个2
vec4.push_back(23); // 尾插23
// 参数1:插入的位置,begin返回值一个迭代器指针,指向第一个元素
// +2表示向后移动两位
// 参数2:新插入的元素
vec4.insert(vec4.begin()+2,4);
// 修改元素
vec4[0] = 1;
vec4[vec4.size()-3] = -222;
vec4.pop_back(); // 删除最后一个元素
// // 删除倒数第2个元素
// 参数:删除的位置,end函数返回的迭代器指针指向最后一个元素的后面
vec4.erase(vec4.end()-2);
// 在倒数第二个位置插入元素888
vec4.insert(vec4.end()-1,888);
cout << "第一个元素:" << vec4.front() << endl;
cout << "最后一个元素:" << vec4.back() << endl;
// 清空
// vec4.clear();
// for-each
for(int i:vec4)
cout << i << " ";
cout << endl;
// 迭代器遍历:(略)
return 0;
}
2.2.1.3 list 列表
list由双向链表实现,元素的内存空间是不连续的,因此更高效地进行插入删除操作,但是不擅长随机存取。
#include <iostream>
#include <list> // 列表
using namespace std;
int main()
{
list<int> lis1; // 创建一个长度为0的int向量
cout << lis1.empty() << endl; // 判断是否为空
list<int> lis2(lis1); // 拷贝构造函数
cout << lis2.size() << endl; // 0
list<int> lis3(5); // 5个0
list<int> lis4(5,2); // 5个2
lis4.push_back(9); // 尾插
lis4.push_front(-1); // 头插
// 在第2个位置插入元素
lis4.insert(++lis4.begin(),3);
// 获取指向第一个元素的迭代器指针
list<int>::iterator iter = lis4.begin();
// 移动指针到第4个位置
advance(iter,3);
// 在第4个位置插入元素4
lis4.insert(iter,4);
// 在倒数第三个位置插入元素-33
iter = lis4.end();
advance(iter,-2);
lis4.insert(iter,-33);
// for-each
for(int i:lis4)
{
cout << i << " ";
}
cout << endl;
lis4.pop_back(); // 删除最后一个元素
lis4.pop_front(); // 删除第一个元素
iter = lis4.begin();
advance(iter,4);
lis4.erase(iter); // 删除第五个元素
// 修改倒数第一个元素
iter = --lis4.end();
*iter = 679;
// 排序
lis4.sort();
lis4.clear(); // 清空
for(int i:lis4)
{
cout << i << " ";
}
cout << endl;
return 0;
}
2.2.1.4 deque 队列
deque是一种均衡的顺序容器,几乎兼容所有的vector和list的接口,性能介于二者之间(两端存取性能较强)。
代码略。
2.2.2 关联容器
关联容器对外没有顺序,内部仍然有排序特点。内部数据以键值对(key-value pair)的方式存储。
map是一种单重键值对映射,键需要具有唯一性,而值可以重复,通常使用键寻找值。
#include <iostream>
#include <map> // 单重键值对映射
using namespace std;
int main()
{
map<string,int> m; // 创建一个map对象
// 添加键值对
m["height"] = 177;
m.insert(pair<string,int>("age",22));
m["height"] = 178; // 已经存在则修改
m.insert(pair<string,int>("age",23)); // 已经存在则无效
cout << m.size() << endl; // 2
// 通过键取出值
cout << m["height"] << " " << m["age"] << endl;
// 取出的键值对不存在,则创建一个
cout << m["weight"] << endl; // 0
cout << m.size() << endl; // 3
// cout << m.at("income") << endl; 终止
// 获取某个键的迭代器指针
map<string,int>::iterator iter = m.find("income");
if(iter == m.end())
{
cout << "没有此键" << endl;
}else
{
cout << "有此键,值=" << iter->second << endl;
}
m.clear(); // 清空
// 遍历只支持迭代器(略)
return 0;
}
2.3 迭代器 iterator
迭代器可以遍历所有的容器,在创建迭代器时,可以使用容器的begin和end函数,分别拿到一个指向第一个元素和最后一个元素之后的迭代器。
迭代器分为只读迭代器(const_interator)和读写迭代器(iterator)。
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <list>
#include <deque>
#include <map>
using namespace std;
int main()
{
string s = "fgjksdhj";
for(string::const_iterator iter = s.begin();iter!=s.end();iter++)
{
cout << *iter << endl;
}
array<double,5> arr;
for(int i=0;i<arr.size();i++)
arr.at(i) = i+1;
for(array<double,5>::iterator iter = arr.begin();iter!=arr.end();iter++)
{
*iter = *iter+1;
cout << *iter << endl;
}
vector<string> v(4,"AAA");
for(vector<string>::const_iterator iter = v.begin();iter!=v.end();iter++)
cout << *iter << endl;
list<string> l(4,"AAA");
for(list<string>::const_iterator iter = l.begin();iter!=l.end();iter++)
cout << *iter << endl;
deque<int> d(4,666);
for(deque<int>::const_iterator iter = d.begin();iter!=d.end();iter++)
cout << *iter << endl;
map<string,string> m;
m["name"] = "David";
m["city"] = "Jinan";
m["aaa"] = "bbbb";
for(map<string,string>::const_iterator iter = m.begin();iter!=m.end();
iter++)
{
cout << iter->first << " " << iter->second << endl;
}
return 0;
}