string迭代器的实现
大约 4 分钟
string迭代器的实现
string str1 = "hello world!";//str1叫容器吗?
叫容器,其底层放了一组的字符,也是容器。 若想用指针遍历其底层字符串数组,我们并不清楚它的数组名,那如何指向它的数组名?此时就需要我们的容器的迭代器了。
。迭代器是一个变量,相当于容器和操纵容器的算法之间的中介。迭代器可以指向容器中的某个元素,通过迭代器就可以读写它指向的元素。从这一点上看,迭代器和指针类似。
不同容器底层数据结构不一样,每一种容器都有自己的迭代器,迭代器按照定义方式分成以下四种:
正向迭代器
容器类名::iterator 迭代器名;
常量正向迭代器
容器类名::const_iterator 迭代器名;
反向迭代器
容器类名::reverse_iterator 迭代器名;
常量反向迭代器
容器类名::const_reverse_iterator 迭代器名;
string str1 = "hello world!";//str1叫容器吗?
//iterator即容器的迭代器
string::iterator it = str1.begin();
for (; it!=str1.end(); ++it)
{
cout << *it << " ";
}
cout << endl;

str1对象中存入了各种各样的字符,字符串类型底层的成员变量为私有的,我们无法看见。
容器有一个begin()方法,begin()返回它底层的迭代器的表示,it迭代器指向容器的首元素。
容器中还有一个end()方法,end()表示容器中最后一个元素的后继位置,循环中it!=end(),++it,将其遍历一遍。
底层无论是数组还是链表什么的,如何从当前元素遍历到下一个元素,我们不需要操心;容器底层元素真真正正从一个元素跑到下一个元素,不同数据结构,不同差异都封装在迭代器++运算符重载函数中。
迭代器还需要提供 * 运算符重载,访问迭代器所迭代元素的值,迭代器解引用访问的就是容器底层数据。
实现迭代器iterator:
class String
{
public:
String(const char *p = nullptr)
{
if (p != nullptr)
{
_pstr = new char[strlen(p) + 1];
strcpy(_pstr, p);
}
else
{
_pstr = new char[1];
*_pstr = '0';
}
}
~String()
{
delete[]_pstr;
_pstr = nullptr;
}
String(const String &str)
{
_pstr = new char[strlen(str._pstr) + 1];
strcpy(_pstr, str._pstr);
}
String& operator=(const String &str)
{
if (this == &str)
{
return *this;
}
delete[]_pstr;
_pstr = new char[strlen(_pstr) + 1];
strcpy(_pstr, str._pstr);
return *this;
}
bool operator>(const String &str)const
{
return strcmp(_pstr, str._pstr) > 0;
}
bool operator<(const String &str)const
{
return strcmp(_pstr, str._pstr) < 0;
}
bool operator==(const String &str)const
{
return strcmp(_pstr, str._pstr) == 0;
}
int length()const
{
return strlen(_pstr);
}
char& operator[](int index)
{
return _pstr[index];
}
const char& operator[](int index)const
{
return _pstr[index];
}
const char* c_str()const//返回字符串底层管理的char*,返回为const char*
{
return _pstr;
}
//给String字符串类型提供迭代器iterator的实现
class iterator
{
public:
iterator(char *p = nullptr):_p(p){}
bool operator!=(const iterator &it)
{
return _p != it._p;
}
void operator++()//迭代器前置++;后置++效率低
{
++_p;
}
char& operator*()
{
return *_p;
}
private:
char *_p;
};
iterator begin()//返回容器底层首元素迭代器的表示
{
return iterator(_pstr);
}
iterator end()//返沪容器末尾元素后继位置的迭代器的表示
{
return iterator(_pstr + length());
}
private:
char *_pstr;
friend ostream& operator<<(ostream &out, const String &str);
friend String operator+(const String &lhs, const String &rhs);
};
String operator+(const String &lhs, const String &rhs)
{
String tmp;
tmp._pstr = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
strcpy(tmp._pstr, lhs._pstr);
strcat(tmp._pstr, rhs._pstr);
return tmp;
}
ostream& operator<<(ostream &out, const String &str)
{
out << str._pstr;
return out;
}
int main()
{
String str1 = "hello world!";//str1叫容器吗?
//iterator即容器的迭代器
String::iterator it = str1.begin();
//auto it = str1.begin();//自动推导类型
for (; it!=str1.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
}
auto
//String::iterator it = str1.begin();
auto it = str1.begin();//自动推导类型
auto不是一个类型的“声明”,而是一个“占位符”,编译器在会将auto为变量实际的类型。 使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。它自动推导变量类型是根据“=”右侧的变量类型决定的。
foreach
C++11标准中的foreach方式来遍历容器内部元素的值:其底层还是通过进行遍历的
- 如果自定义类型没有迭代器的实现,则不能用foreach方法遍历
//C++11 foreach方式来遍历容器内部元素的值
for (char ch : str1)
{
cout << ch << " ";
}
cout << endl;