目录
容器
1.标准模板库STL
2.概念
3.顺序容器
(1)array数组
(2)vector向量
(3)list列表
(4)deque 队列
4.关联容器
5.迭代器
面向对象核心
继承
概念
构造函数
1.派生类与基类构造函数的关系
2.解决方案
(1)补充基类的无参构造函数
(2)手动在派生类中调用基类构造函数
1.透传构造
容器
1.标准模板库STL
标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。虽说它主要出现到了C++中,但是在被引入C++之前该技术就已经存在了很长时间。
STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
2.概念
容器是用来存储数据的集合,数据元素可以是任何类型(因为是使用模板实现)。
容器类的使用,都要引入对应的头文件。
3.顺序容器
顺序容器中每个元素都有固定的位置并呈线性排布,除非使用删除或者插入的操作改变元素的位置。
(1)array数组
array是C++11新增的容器类型,与传统数组相比更加的安全、易于使用。array数组是定长的。没有办法方便的进行伸缩。
#include <iostream>
#include <array>
using namespace std;int main()
{// 创建一个长度为5的int数组array<int,5> arr = {1,2,3}; // 后面两位补零cout << arr[0] << endl; // 1cout << arr[4] << endl; // 0cout << arr.at(2) << endl; // 3arr[3] = 200;arr[4] = 300;for(int i = 0; i < arr.size(); i++){cout << arr.at(i) << " ";}cout << endl;// for eachfor(int i : arr){cout << i << endl;}return 0;
}
(2)vector向量
vector内部是由数组实现的,比较适合进行随机的存取操作,而不擅长插入删除操作。不是定长的。
#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> vec(5); // 创建一个长度为5的int向量cout<<vec.size()<<endl; // 5// 增// 向后追加单元素vec.push_back(111);cout<<vec.size()<<endl; // 6vec.insert(vec.begin()+1,666);// begin()可以返回指向第一个元素的迭代器指针,+1是在第二个位置上插入333//改vec.at(0)=777;vec[2]=555;vec.at(3)=444;vec.at(4)=333;vec.at(5)=222;for(int i:vec){cout<<i<<" ";}cout<<endl;// 删除// 删除最后一个元素vec.pop_back();for(int i:vec){cout<<i<<" ";}cout<<endl;vec.erase(vec.begin()+1);//删除第二个元素vec.erase(vec.end()-2);//删除倒数第二个元素for(int i:vec){cout<<i<<" ";}cout<<endl;//查cout<<"vec[0]="<<vec.at(0)<<endl;cout<<"vec[1]="<<vec[1]<<endl;for(size_t i=0;i<vec.size();i++){cout<<vec.at(i)<<" ";}cout<<endl;//判断是否为空,0:非空 1:空cout<<vec.empty()<<endl;vec.clear();cout<<vec.empty()<<endl;return 0;
}
(3)list列表
list内部是由双向链表实现,内存空间不连续,不支持下标。优点:可以高效的删除和插入操作,但是不适合随机的存取。
#include <iostream>
#include <list>
using namespace std;int main()
{// list<string> lis1;// list<string> lis2={"hello","world"};// 创建一个长度为5的列表,每个元素都是hellolist<string> lis(5,"hello");for(string i:lis){cout<<i<<" ";}cout<<endl;// 增lis.push_back("world");// 向后追加单元素lis.push_front("heiheihei");// 向前追加单元素lis.insert(++lis.begin(),"111");// 在第二个位置上插入"111"for(string i:lis){cout<<i<<" ";}cout<<endl;//删除lis.pop_back();// 删除最后一个元素lis.pop_front(); // 删除第一个元素for(string i:lis){cout<<i<<" ";}cout<<endl;list<string>::iterator iter=lis.begin();// 保存迭代器指针advance(iter,1); // 移动迭代器指针到固定位置lis.insert(iter,"222");for(string i:lis){cout<<i<<" ";}cout<<endl;// 删除最后一个元素// iter=lis.end();// iter--;// lis.erase(iter);iter=lis.begin();advance(iter,1);lis.erase(iter);for(string i:lis){cout<<i<<" ";}cout<<endl;// 返回第一个元素的引用cout << lis.front() << endl;// 返回最后一个元素的引用cout << lis.back() << endl;//改iter=lis.end();advance(iter,2);*iter="200";for(string i:lis){cout<<i<<" ";}cout<<endl;//查cout<<"iter="<<*iter<<endl;// 不能使用普通循环遍历,因为不支持下标// 清空lis.clear();cout << lis.size() << endl; // 0return 0;
}
(4)deque 队列
deque几乎支持所有vector的API,性能位于vector与list两者之间,是最擅长两端存取的顺序容器。
#include <iostream>
#include <deque>
using namespace std;int main()
{deque<int> deq(5); // 创建一个长度为5的int队列cout<<deq.size()<<endl; // 5// 增// 向后追加单元素deq.push_back(111);cout<<deq.size()<<endl; // 6deq.insert(deq.begin()+1,666);// begin()可以返回指向第一个元素的迭代器指针,+1是在第二个位置上插入333//改deq.at(0)=777;deq[2]=555;deq.at(3)=444;deq.at(4)=333;deq.at(5)=222;for(int i:deq){cout<<i<<" ";}cout<<endl;// 删除// 删除最后一个元素deq.pop_back();for(int i:deq){cout<<i<<" ";}cout<<endl;deq.erase(deq.begin()+1);//删除第二个元素deq.erase(deq.end()-2);//删除倒数第二个元素for(int i:deq){cout<<i<<" ";}cout<<endl;//查cout<<"deq[0]="<<deq.at(0)<<endl;cout<<"deq[1]="<<deq[1]<<endl;for(size_t i=0;i<deq.size();i++){cout<<deq.at(i)<<" ";}cout<<endl;//判断是否为空,0:非空 1:空cout<<deq.empty()<<endl;deq.clear();cout<<deq.empty()<<endl;return 0;
}
4.关联容器
关联容器的各个元素之间没有严格顺序,虽然内部具有排序特点,但是在使用时没有任何顺序相关接口。最常见的关联容器就是map-键值对映射。
对于map而言,键具有唯一性,通常使用字符串类型,值可以是任何类型。通过键可以找到对应的值。
#include <iostream>
#include <map>
using namespace std;int main()
{//列表初始化map<string,int> ma1={{"身高",185},{"年龄",22}};//有两个元素cout<<ma1.size()<<endl; //2//创建一个元素数据为0的键值对对象map<string,int> ma;cout<<ma.size()<<endl; //0//增ma["身高"]=180;ma.insert(pair<string,int>("体重",120 ));//查cout<<ma["身高"]<<endl; //180cout<<ma["体重"]<<endl; //120//改ma["身高"]=175;cout<<ma["身高"]<<endl; //175//删int re=ma.erase("身高");cout<<"身高删除 "<<re<<endl; //身高删除 1cout << ma.size() << endl; //1re = ma.erase("学号");cout << re << endl; //0if(ma.find("身高")==ma.end()){cout<<"没有找到身高元素"<<endl;}else{cout<<ma["身高"]<<endl;}ma.clear();cout<<ma.size()<<endl; //0return 0;
}
5.迭代器
迭代器是一个特殊的指针,主要用于容器的元素读写以及遍历。
如果迭代器不进行修改操作,仅以使用只读迭代器,const_iterator,反之则使用iterator。
#include <iostream>
#include <map>
#include <array>
#include <vector>
#include <list>
#include <deque>using namespace std;int main()
{string s="abcd";cout<<"迭代器遍历string"<<endl;for(string::const_iterator iter=s.begin();iter!=s.end();iter++){cout<<*iter<<" ";}cout<<endl;cout << "--------------" <<endl;array<int,5> arr={1,2,3,4,5};cout<<"迭代器遍历array"<<endl;for(array<int,5>::const_iterator iter=arr.begin();iter!=arr.end();iter++){cout<<*iter<<" ";}cout<<endl;cout << "--------------" <<endl;vector<string> vec(6,"hello");cout<<"迭代器遍历vector"<<endl;for(vector<string>::const_iterator iter = vec.begin();iter != vec.end();iter++){cout<<*iter<<" ";}cout<<endl;cout << "--------------" <<endl;list<string>lis(6,"world");cout<<" 迭代器遍历list"<<endl;for(list<string>::const_iterator iter = lis.begin();iter != lis.end();iter++){cout<<*iter<<" ";}cout<<endl;cout << "--------------" <<endl;deque<string> de(6,"haha");cout<<"迭代器遍历deque"<<endl;for(deque<string>::iterator iter = de.begin(); iter != de.end(); ++iter){cout<<*iter<<" ";}cout<<endl;cout << "--------------" <<endl;map<string,int>ma;ma["年龄"] = 22;ma["身高"] = 175;ma["体重"] = 60;cout<<"迭代器遍历map"<<endl;for(map<string,int>::const_iterator iter = ma.begin();iter != ma.end();iter++){ // first 是键,second 是值cout << iter->first << " " << iter->second << endl;}return 0;
}
面向对象核心
继承
概念
继承就是面向对象的三大特性之一,体现了代码复用的思想。
继承就是在一个已存在的类的基础上,建立一个新的类,并拥有其特性。
1.已存在的类被称为“基类”或者“父类”
2.新建立的类被称为“派生类”或者“子类”
#include <iostream>
using namespace std;// 基类
class Father
{
private:string name = "张";
public:void set_name(string name){this->name = name;}string get_name(){return name;}void work(){cout << "我的工作是厨师,我负责炒菜" << endl;}
};// 派生类
class Son:public Father
{
};int main()
{Son son;cout << son.get_name() << endl;son.work();return 0;
}
上面的代码,Son类的功能几乎与Father类重叠,在实际的使用过程中,派生类会做出一些与基类的差异化。
●修改继承来的基类内容
属性:1、公有属性可以直接更改。更改后基类中的属性也会改变,因为改的是同一份变量
2、私有属性,需要使用基类公有函数进行更改。
行为:函数隐藏,通过派生类实现一个同名同参数的函数,来隐藏基类的函数。
●新增派生类的内容
#include <iostream>
using namespace std;// 基类
class Father
{
private:string name = "张";
public:void set_name(string name){this->name = name;}string get_name(){return name;}void work(){cout << "我的工作是厨师,我负责炒菜" << endl;}
};// 派生类
class Son:public Father
{
public:void init(){set_name("王");}void work(){cout << "我的工作是司机" << endl;}void game(){cout << "开挖掘机" << endl;}
};int main()
{Son son;son.init();cout << son.get_name() << endl;son.work(); son.game();son.Father::work();return 0;
}
基类和派生类都是相对的,一个类可能存在又是基类又是派生类的情况,取决于那两个类进行比较。
构造函数
1.派生类与基类构造函数的关系
构造函数与析构函数不能被继承。
#include <iostream>
using namespace std;// 基类
class Father
{
private:string name;
public:Father(string name):name(name){} // 有参构造函数string get_name(){return name;}
};// 派生类
class Son:public Father
{
};int main()
{
// Son s; // 找不到基类的无参构造函数
// Son s("张"); // 找不派生类的有参构造函数return 0;
}
2.解决方案
(1)补充基类的无参构造函数
#include <iostream>
using namespace std;// 基类
class Father
{
private:string name;
public:// 无参构造函数Father():name("张"){}// 有参构造函数Father(string name):name(name){}string get_name(){return name;}
};// 派生类
class Son:public Father
{
public:
};int main()
{Son s; cout << s.get_name() << endl;return 0;
}
(2)手动在派生类中调用基类构造函数
1.透传构造
在派生类的构造函数中,调用基类的构造函数,实际上编译器自动添加的派生类构造函数,调用基类无参构造函数时,就是采用的这种方式。
#include <iostream>
using namespace std;// 基类
class Father
{
private:string name;
public:// 有参构造函数Father(string name):name(name){}string get_name(){return name;}
};// 派生类
class Son:public Father
{
public:// 编译器会自动添加构造函数,透传调用基类无参构造函数(透传构造)// Son():Father(){}// 手动添加构造函数,透传构造Son():Father("王"){}// 有参构造函数,调用基类有参构造函数Son(string fn):Father(fn){}
};int main()
{Son s;cout << s.get_name() << endl;Son s1("张");cout << s1.get_name() << endl;return 0;
}