文章目录
- [1. 什么是string?](#1. 什么是string?)
- [2. auto和范围for的使用](#2. auto和范围for的使用)
-
- [2. 1 auto](#2. 1 auto)
- [2. 2 范围for](#2. 2 范围for)
- [3. 迭代器的概念、const string的概念](#3. 迭代器的概念、const string的概念)
-
- [3. 1 迭代器的概念](#3. 1 迭代器的概念)
- [3. 2 const string的概念](#3. 2 const string的概念)
1. 什么是string?
在了解什么是string之前,我们首先需要知道字符串是什么。在C语言中,字符串是指以'\0'结尾的一些集合。同时为了操作方便,C语言也提供了一些库函数用来操作这些字符串。
但是,这些函数与字符串是分离开的,不符合OOP的思想------(面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。)。同时需要用户自己管理底层空间,稍不留神就会出现越界访问。
所以为了替代C语言原本令人诟病的字符串体系,就有了string的诞生。因此,可以认为string是C++的字符串控制体系。
2. auto和范围for的使用
2. 1 auto
在C++11之后,标准委员会赋予auto全新的意义:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
auto作为语法糖,实际上是为了方便程序员进行更方便的操作。下面的代码就是全部的使用。
cpp
C++20开始支持
//void Func1(auto x)
//{
//
//}
//auto做函数返回值,以函数实际 return 返回的值的类型为类型
//不建议使用auto做函数的返回值。因为函数返回值使用auto的话,确认函数返回值的类型就会变得麻烦
auto Func(int x)
{
auto y = x;
return y;
}
//auto和范围for的使用
int main()
{
//auto的使用
auto x1 = 1;//auto根据实际对象(1)来自动推断类型
auto x2 = 1.1;
auto x3 = "hello world";
int x4 = 1;
int& x5 = x4;
auto x6 = x5;//auto无法判断类型是否是引用,只能根据引用的对象来判断类型,也就是引用对象的类型就是auto的类型
//然而 auto 诞生的主要目的不是代替这些类型。而是代替一些过长的类型
//例如
list<int> It;//定义一个list对象It
It.push_back(1);
It.push_back(2);
It.push_back(3);
It.push_back(4);//往对象里面尾插1 2 3 4
list<int>::iterator it1 = It.begin();//定义一个list的迭代器it1,it1指向list对象It的第一个位置,list<int>::iterator是类型
auto it2 = It.begin();//定义一个list的迭代器it2,it2指向list对象It的第一个位置,auto自动推导类型,因此省去了写前面的一长串
while (it2 != It.end())
{
it2++;
}
//另一个例子
std::map<std::string, std::string> dict;
std::map<std::string, std::string>::iterator dit1 = dict.begin();
auto dit2 = dict.begin();//auto代替的就是 std::map<std::string, std::string>::iterator 这一迭代器的类型
//因此auto可以减轻程序员的编写负担。要是经常需要写那么长一串的类型的话,本来就没剩几根的头发也是岌岌可危了
//函数的形参为auto,C++20之后才开始支持
//Func1();
//函数返回类型为auto,参数为int,函数返回值为int
Func(1);
return 0;
2. 2 范围for
范围for的出现和auto一致,均是为了方便程序员而推出的语法糖。
cpp
int main()
{
// 范围for的使用
// 适用于容器遍历和数组遍历
// 原理:范围for底层是迭代器
string s1("hello world");
//范围for会把右边的参数自动赋值给左边的变量,左边的变量自动++,直到为空
//自动取容器的数据赋值给左边的对象
//自动++,自动判断结束
for (auto ch : s1)
{
//s1的值自动赋值给ch,ch自动++
cout << ch << " ";
}
cout << endl;
//由于范围for是把右边的值赋值给左边的变量,再对左边的变量进行操作,因此就会出现
for (auto ch : s1)
{
ch++;
cout << ch << " ";//这里s1的值成功++,并且打印出来
}
cout << endl;
for (auto ch : s1)
{
cout << ch << " ";//这里s1的值不变。说明上面的++是将s1拷贝给ch,再在ch中操作,没有对s1本身做出改变
}
cout << endl;
//如果想要在范围for里面改变s1,就需要使用引用
for (auto& ch : s1)//引用,传址操作
{
ch++;
}
for (auto ch : s1)
{
cout << ch << " ";
}
cout << endl;
//还有另一种情况需要使用引用。当赋值的本体过大,因此拷贝的代价过大,就需要使用引用
//那么,使用引用之后不想要对本体做出改变怎么办?使用const
for (const auto& ch : s1)
{
//ch++;//编译器报错
}
//范围for的使用对象除了容器,还有数组
int a[] = { 1,2,3,4,5,6,7,8 };
//正常使用for循环去打印
for (size_t i = 0; i < sizeof(a) / sizeof(int); i++)
{
cout << a[i] << " ";
}
cout << endl;
//使用范围for去打印
for (auto ch : a)
{
cout << ch << " ";
}
cout << endl;
return 0;
}
3. 迭代器的概念、const string的概念
3. 1 迭代器的概念
在了解string是怎么使用之前,我们首先需要知道迭代器的存在。
迭代器(iterator),可以理解为一种像指针、能完成指针所有操作的对象。其定义为:提供一种方法,使之能够依次寻访某个容器所包含的所有元素,而又无需暴露该容器底层的结构。
由于迭代器本身是抽象的概念,所以会配合下面的代码进行说明。
cpp
//迭代器的概念
int main()
{
string s1("Hello world!");
//在C++中,我们想要访问string中的字符串,有两种方式
//1.下标
//这里之所以能使用下标,是因为在string这个容器中,有关于[]运算符的重载,所以能直接使用[]
//下标的使用的是有前提的。就是对象的存储空间必须是线性的。如果是链表或者树,那么下标的性能就会大幅下降
cout << "下标:";
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
//2.迭代器
cout << "迭代器:";
//string::iterator 说明这是容器 string 的迭代器。it1是实例化的迭代器,可以理解成像s1的指针。但是绝对不是指针,迭代器是全新的概念
string::iterator it1 = s1.begin();//it1指向的是s1的开头
while (it1 != s1.end())//这里的end指向的不是world的d,而是d的下一位,通常是"\0"
{
cout << *(it1++) << " ";
}
cout << endl;
//迭代器也有反向的
cout << "反向编译器:";
string::reverse_iterator rit = s1.rbegin();//这里rit指向的是world中的d
while (rit != s1.rend())//这里的rend指向的也不是hello中的h,而是h的前一位
{
cout << *(rit)++ << " ";//这里的++意味着,反向迭代器不仅仅是定义的反向,运算符重载的方向也是反向的
}
return 0;
3. 2 const string的概念
cpp
//const string 对象
int main()
{
string s1("Hello world!");
//const string对象必须使用const修饰的迭代器
const string s2(s1);
//const_iterator 和 const iterator的区别:前者限定的是迭代器指向的内容,后者限定的是迭代器本身
//限定迭代器本身的话,就会因为迭代器无法改变,而没办法让 it1++ 访问后面的内容
//string::const_iterator it1 = s2.begin();
auto it1 = s2.begin();
while (it1 != s2.end())
{
//*it1 += 1;//const 修饰的对象,无法改变大小
cout << *it1++ << " ";//但是可以改变迭代器的大小,从而改变指向的位置
}
cout << endl;
//const反向迭代器
string::const_reverse_iterator rit1 = s2.rbegin();
while (rit1 != s2.rend())
{
cout << *rit1++ << " ";
}
cout << endl;
return 0;
}