一、标准模板库STL(standard template library)
STL是泛型编程的经典案例
泛型编程简介:泛型编程是一种编程范式,旨在实现可重用性、类型安全和抽象性。
它允许开发人员编写适用于多种数据类型的代码,而无需为每种数据类型编写重复代码
//https://www.cnblogs.com/shijingjing07/p/5593399.html
1.vector数组
#include <algorithm>
vector向量相当于一个数组
在内存中分配一块连续的内存空间进行存储。支持不指定vector大小的存储。
通常此默认的内存分配能完成大部分情况下的存储
优点:
可以不指定大小,使用push_back、pop_back来进行动态操作
随机访问方便,即支持[]操作符和vector.at()
节省空间
缺点:
在内部进行插入删除操作效率低
只能在vector的最后进行push和pop,不能再vector的头进行push和pop
当动态添加的数据超过vector默认分配的大小时要进行整体的重新分配、拷贝与释放
参考://https://www.cnblogs.com/Nonono-nw/p/3462183.html
eg:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void)
{
#if 1
vector<int> myvec;
myvec.push_back(123);
myvec.push_back(34);
myvec.push_back(64);
#if 0
for(int i=0;i<myvec.size();i++){
cout<<myvec[i]<<",";
// cout<<myvec.at(i)<<",";
}
cout<<endl;
#endif
// 采用迭代器进行遍历
for (auto iter = myvec.begin(); iter != myvec.end(); iter++)
{
cout << *iter << ",";
}
cout << endl;
sort(myvec.begin(),myvec.end());
//采用foreach
for(auto i:myvec){
cout<<i<<",";
}
cout<<endl;
#if 0
auto iter = myvec.begin();
iter++;
myvec.insert(iter, 100); //执行插入
for (auto iter = myvec.begin(); iter != myvec.end(); iter++)
{
cout << *iter << ",";
}
cout << endl;
#endif
#endif
#if 0
vector <string> myvec;
myvec.push_back("abc");
myvec.push_back("hello");
myvec.push_back("world");
myvec.pop_back();
for(int i=0;i<myvec.size();i++){
//cout<<myvec[i]<<",";
cout<<myvec.at(i)<<",";
}
cout<<endl;
#endif
return 0;
}
2.栈stack
#include <stack>
stack
特点:后进先出
//https://blog.csdn.net/weixin_52341477/article/details/119250698
eg:
#include <iostream>
#include <stack>
using namespace std;
int main(void)
{
stack <double> mystack;
mystack.push(35.6);
mystack.push(0.54);
mystack.push(67.3);
mystack.push(2.6);
#if 0
cout<< mystack.top()<<endl;
mystack.pop();
cout<< mystack.top()<<endl;
#endif
while(!mystack.empty()){ //循环 出栈
cout<< mystack.top()<<endl;
mystack.pop();
}
return 0;
}
3.队列queue
queue
特点:先进先出
//https://www.cnblogs.com/qingyuanjushi/p/5911090.html
eg:
#include <iostream>
#include <queue>
using namespace std;
int main(void)
{
queue<int> myqueue;
myqueue.push(43);
myqueue.push(75);
myqueue.push(23);
myqueue.push(66);
#if 0
cout<<myqueue.front()<<endl;
myqueue.pop();
cout<<myqueue.front()<<endl;
#endif
while (!myqueue.empty()) //循环出队列
{
cout << myqueue.front() << endl;
myqueue.pop();
}
return 0;
}
4.list链表
#include <list>
list 双向链表
每一个结点都包括一个信息快Info、一个前驱指针Pre、一个后驱指针Post。
可以不分配必须的内存大小方便的进行添加和删除操作。使用的是非连续的内存空间进行存储。
优点:
不使用连续内存完成动态操作
在内部方便的进行插入和删除操作
可在两端进行push、pop
缺点:
不能进行内部的随机访问,即不支持[ ]操作符和vector.at()
相对于verctor占用内存多
//https://blog.csdn.net/yas12345678/article/details/52601578/
eg:
#include <iostream>
#include <list>
using namespace std;
int main(void)
{
list <int> mylist;
//插入
mylist.push_front(13);
mylist.push_front(74);
mylist.push_front(96);
mylist.push_back(100);
//删除
// mylist.pop_back(); //尾删
// mylist.pop_front(); //头删
mylist.sort();
mylist.reverse();
for(auto iter = mylist.begin(); iter!= mylist.end(); iter++ ){
cout<<*iter<<",";
}
cout<<endl;
return 0;
}
小结:
如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector
如果你需要大量的插入和删除,而不关心随机存取,则应使用list
5.map
#include <map>
map的元素是成对的键值/实值,内部的元素依据其值自动排序,map内的相同数值的元素只能出现一次,
Multimap内可包含多个数值相同的元素,内部由二叉树实现(实际上基于红黑树(RB-tree)实现),便于查找。
//https://blog.csdn.net/yyhyyhy/article/details/124531264
eg:
#include <iostream>
#include <map>
using namespace std;
int main(void)
{
map <string, double> price;
price["ruler"] = 2.6;
price.insert({string("notebook"),14.5});
price["pen"] = 5.3;
string item;
while(1){
cin>>item;
if(item=="quit"){
break;
}
cout<<"该商品的价格:"<<price[item]<<endl;
}
return 0;
}
二、转换函数(类型转换)
1.隐式转换相关
在C++中也有类型转换的需求
基本数据类型,可以直接显示转换,或者隐式转换
c风格的转换 (int)3.51
C++风格的转换 int(3.51)
面向对象(自定义类) 的转换,需要写转换函数,然后便可以显示转换或隐式转换
基本语法:
operator 类型( )
{
实现转换的语句;
}
基本规则:
转换函数只能是成员函数,无返回值,空参数。
不能定义到void的转换,也不允许转换成数组或者函数类型。
转换常定义为const形式,原因是它并不改变数据成员的值。
类似于运算符重载,本质:重载
为了避免隐式转换(安全问题), explicit关键字用来修饰类转换函数,
explicit 还可以修饰构造函数,避免隐式转换
转换函数 慎用
eg:
#include <iostream>
using namespace std;
class A
{
private:
int val;
public:
A(int x=0): val(x) {
}
void set_val(int x) {
val = x;
}
void print_val(void) const {
cout<<"val:"<<val<<endl;
}
explicit operator int() {
return val;
}
};
int main(void)
{
A a1(534);
a1.print_val();
int ret = (int)a1; //把a1强转成 int类型 // A --> int
cout<<ret<<endl;
//有了转换函数,会大量出现编译器自动执行 隐式转换 (容易出现安全问题)
//为了防止隐式转换,可以添加关键字explicit
//explicit 也可以修饰构造函数,防止隐式转换
cout<<(int)a1<<endl; //只能显示转换
#if 0
cout<<a1<<endl;
A a2(54);
A a3 = a2+a1;
cout<<a3<<endl;
#endif
#include <iostream>
using namespace std;
class A
{
private:
int val;
public:
explicit A(int x=0): val(x) { //修饰构造函数 防止隐式转换 更加安全
}
void set_val(int x) {
val = x;
}
void print_val(void) const {
cout<<"val:"<<val<<endl;
}
};
#if 0
A fun(int i)
{
return i;
}
#endif
int main(void)
{
A a1(534);
a1.print_val();
#if 0
A a2 = 33; //隐式转换 A a2(33)
a2.print_val();
#endif
//A a2=33; //explicit 修饰构造函数,防止隐式转换
A a3(33);
return 0;
}
2.标准的转换函数:
C++提供了一些标准转换函数,建议使用标准转换函数进行类型转换
分别有:reinterpret_cast、const_cast、static_cast、dynamic_cast
1. reinterpret_cast<new type>(expression)
将一个类型的指针转换为另一个类型的指针,它也允许从一个指针转换为整数类型
2. const_cast< new type>( expression)
const指针与普通指针间的相互转换,注意:不能将非常量指针变量转换为普通变量
3. static_cast<new type>(expression)
主要用于基本类型间的相互转换,和具有继承关系间的类型转换
4. dynamic_cast<newtype>(expression)
只有类中含有虚函数才能用dynamic_cast;仅能在继承类对象间转换
dynamic_cast具有类型检查的功能,比static_cast更安全
注意:其实只有dynamic_cast,是具有安全检查的类型转换
#include <iostream>
using namespace std;
//多态: 同一接口,面向不同对象,调用的方法不同
class Animal
{
public:
virtual void eat(){
cout<<"animal eat"<<endl;
}
};
class Cat:public Animal
{
public:
void eat(){
cout<<"cat eat function"<<endl;
}
};
class Dog:public Animal
{
public:
void eat(){
cout<<"dog eat function"<<endl;
}
};
int main(void)
{
Cat cat1;
Animal *ptr = &cat1;
//ptr->eat();
Cat *p = dynamic_cast<Cat *> (ptr);
//在标准转换函数中,只有dynamic_cast,具有安全检查,其它的等同于强转
p->eat();
return 0;
}