C++迭代器一:string字符串对象的迭代器iterator实现、实现vector容器的迭代器
文章目录一、string字符串对象的迭代器iterator实现二、实现vector容器的迭代器一、string字符串对象的迭代器iterator实现我们先来看这个例子:使用库中的string,那么string的对象str1叫容器吗?string str1 = "hello world!";//str1叫容器吗?叫容器,其底层放了一组char类型的字符,也是容器。若想用指针遍历其底层字符...
一、string字符串对象的迭代器iterator实现
我们先来看这个例子:使用库中的string,那么string的对象str1叫容器吗?
string str1 = "hello world!";//str1叫容器吗?
叫容器,其底层放了一组char类型的字符,也是容器。
若想用指针遍历其底层字符串数组,我们并不清楚它的数组名,那如何指向它的数组名?此时就需要我们的容器的迭代器了。
迭代器:要访问顺序容器和关联容器中的元素,需要通过"迭代器(iterator)"进行,提供一种统一的方式,来透明的遍历容器。迭代器是一个变量,相当于容器和操纵容器的算法之间的中介。迭代器可以指向容器中的某个元素,通过迭代器就可以读写它指向的元素。从这一点上看,迭代器和指针类似。
不同容器底层数据结构不一样,每一种容器都有自己的迭代器,迭代器按照定义方式分成以下四种:
1.正向迭代器,定义方法如下:
容器类名::iterator 迭代器名;
2.常量正向迭代器,定义方法如下:
容器类名::const_iterator 迭代器名;
3. 反向迭代器,定义方法如下:
容器类名::reverse_iterator 迭代器名;
4.常量反向迭代器,定义方法如下:
容器类名::const_reverse_iterator 迭代器名;
我们通过迭代器可以解决刚才的问题:
string str1 = "hello world!";//str1叫容器吗?
//iterator即容器的迭代器
string::iterator it = str1.begin();
for (; it!=str1.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
那么这段代码什么意思:
1.str1对象中存入了各种各样的字符,字符串类型底层的成员变量为私有的,我们无法看见。
2.容器有一个begin()方法,begin()返回它底层的迭代器的表示,it迭代器指向容器的首元素。
3.容器中还有一个end()方法,end()表示容器中最后一个元素的后继位置,循环中it!=end(),++it,将其遍历一遍。
4.底层无论是数组还是链表什么的,如何从当前元素遍历到下一个元素,我们不需要操心;容器底层元素真真正正从一个元素跑到下一个元素,不同数据结构,不同差异都封装在迭代器++运算符重载函数中。
5.迭代器还需要提供 * 运算符重载,访问迭代器所迭代元素的值,迭代器解引用访问的就是容器底层数据。
实现迭代器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;
}
执行结果:成功实现迭代器的++
也可以使用替换这句:
//String::iterator it = str1.begin();
auto it = str1.begin();//自动推导类型
auto不是一个类型的“声明”,而是一个“占位符”,编译器在编译期会将auto替换为变量实际的类型。 使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。它自动推导变量类型是根据“=”右侧的变量类型决定的。
我们还可以利用C++11标准中的foreach方式来遍历容器内部元素的值:其底层还是通过迭代器进行遍历的。
//C++11 foreach方式来遍历容器内部元素的值
for (char ch : str1)
{
cout << ch << " ";
}
cout << endl;
来看一下:执行成功
二、实现vector容器的迭代器
泛型算法:给所有容器都可以使用,参数接受的都是容器的迭代器。
我们来实现一下vector容器的迭代器:
//容器的空间配置器
template <typename T>
struct Allocator
{
T* allocate(size_t size)//只负责内存开辟
{
return (T*)malloc(sizeof(T) * size);
}
void deallocate(void *p)//只负责内存释放
{
free(p);
}
void construct(T *p, const T &val)//已经开辟好的内存上,负责对象构造
{
new (p) T(val);//定位new,指定内存上构造val,T(val)拷贝构造
}
void destroy(T *p)//只负责对象析构
{
p->~T();//~T()代表了T类型的析构函数
}
};
template <typename T, typename Alloc = Allocator<T>>
class vector//向量容器
{
public:
vector(int size = 10)//构造
{
//_first = new T[size];
_first = _allocator.allocate(size);
_last = _first;
_end = _first + size;
}
~vector()//析构
{
//delete[]_first;
for (T *p=_first; p!=_last; ++p)
{
_allocator.destroy(p);//把_first指针指向的数组的有效元素析构
}
_allocator.deallocate(_first);//释放堆上的数组内存
_first = _last = _end = nullptr;
}
vector(const vector<T> &rhs)//拷贝构造
{
int size = rhs._end - rhs._first;//空间大小
//_first = new T[size];
_first = _allocator.allocate(size);
int len = rhs._last - rhs._first;//有效元素
for (int i=0; i<len; ++i)
{
//_first[i] = rhs._first[i];
_allocator.construct(_first+i, rhs._first[i]);
}
_last = _first + len;
_end = _first + size;
}
vector<T>& operator=(const vector<T> &rhs)//赋值运算符重载
{
if (this == &rhs)
{
return *this;
}
//delete[]_first;
for (T *p=_first; p!=_last; ++p)
{
_allocator.destory(p);//把_first指针指向的数组的有效元素析构
}
_allocator.deallocate(_first);//释放堆上的数组内存
int size = rhs._end - rhs._first;//空间大小
_first = _allocator.allocate(size);
int len = rhs._last - rhs._first;//有效元素
for (int i=0; i<len; ++i)
{
_allocator.construct(_first+i, rhs._first[i]);
}
_last = _first + len;
_end = _first + size;
return *this;
}
void push_back(const T &val)//尾插
{
if (full())
{
expand();
}
//*_last++ = val;
_allocator.construct(_last, val);//_last指针指向的内存构造一个值为val的对象
_last++;
}
void pop_back()//尾删
{
if (empty()) return;
//--_last;
//不仅要把_last指针--,还需要析构删除的元素
--_last;
_allocator.destroy(_last);
}
T back()const//返回容器末尾元素值
{
return *(_last - 1);
}
bool full()const
{
return _last == _end;
}
bool empty()const
{
return _first == _last;
}
int size()const//返回容器中元素个数
{
return _last - _first;
}
T& operator[](int index)
{
if (index < 0 || index >= size())
{
throw "OutOfRangeException";
}
return _first[index];
}
//迭代器一般实现成容器的嵌套类型
class iterator
{
public:
iterator(T *ptr = nullptr)
:_ptr(ptr){}
bool operator!=(const iterator &it)const
{
return _ptr != it._ptr;
}
void operator++()
{
_ptr++;
}
T& operator*()
{
return *_ptr;
}
const T& operator*()const
{
return *_ptr;
}
private:
T *_ptr;
};
iterator begin()
{
return iterator(_first);
}
iterator end()
{
return iterator(_last);
}
private:
T *_first;//起始数组位置
T *_last;//指向最后一个有效元素后继位置
T *_end;//指向数组空间的后继位置
Alloc _allocator;//定义容器的空间配置器对象
void expand()//扩容
{
int size = _end - _first;
//T *ptmp = new T[2*size];
T *ptmp = _allocator.allocate(2*size);
for (int i=0; i<size; ++i)
{
_allocator.construct(ptmp+i, _first[i]);
//ptmp[i] = _first[i];
}
//delete[]_first;
for (T *p=_first; p!=_last; ++p)
{
_allocator.destroy(p);
}
_allocator.deallocate(_first);
_first = ptmp;
_last = _first + size;
_end = _first + 2*size;
}
};
int main()
{
vector<int> vec;
for (int i=0; i<20; ++i)
{
vec.push_back(rand()%100);
}
int size = vec.size();//[]重载针对vector有意义
for (int i=0; i<size; ++i)
{
cout << vec[i] << " ";//底层是数组,O(1)
}
cout << endl;
vector<int>::iterator it = vec.begin();
//auto it = vec.begin();
for (; it!=vec.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
for(int val : vec)//底层还是通过容器的迭代器来实现遍历的
{
cout << val << " ";
}
cout << endl;
return 0;
}
执行结果:测试成功。
更多推荐
所有评论(0)