目录
string构造接口(Construct string object)
string相比于C语言的字符数组要好用的多,无论是在初始化还是在读写方面都方便许多。
以basic_string
1、 第一个string():无参类型的构造,字符串长度为0。
2、string (const string& str) :拷贝构造
3、string (const string& str, size_t pos, size_t len = npos)
以一个字符串的第pos个字符为起始,长度为len构造一个字符串:
如果构造字符串的过程超过了目标字符串最后一位,那么将拷贝到最后一位停止:
4、string (const char* s) :以字符串为参数构造,有两种形式。
5、string (const char* s, size_t n) :拷贝一个字符串的前n个字符
6、string (size_t n, char c) :构造n个c字符的字符串:
7、string (InputIterator first, InputIterator last) :从first开始到 last结束进行构造字符串:
此外对多个字符串还能进行拼接,使用重载运算符 += 即可:
上面所讲,红色标注的为重点,其他的了解用法即可。
string中也对运算符 [ ]进行了重载,使得可以通过下标来访问元素。
[ ] 运算符重载原型如下:
- char& operator[](size_t i)
- {
- assert(i < s0.size() );
- return _str[i];
- }
并且相比于静态数组,它可以防止溢出。
这里也可以使用范围for:
看起来范围for好像是比用下标访问要方便一点,但是有的情况下用下标访问比较好,比如需要逆置上面的数组时:
上面的数组还有第三种表示方式,就是迭代器。
迭代器是string类里定义的类型,但不是内部类,只是在其中定义,属于string类。
迭代器 iterators是一种行为像指针的类型,但它底层是不是指针不确定,具体要看实现,但是它的用法很像指针,且看他如何访问数组元素:
- string s0("abcd1234");
- string::iterator it = s0.begin();
- while (it != s0.end())
- {
- *it += 1;
- ++it;
- }
- it = s0.begin();
- while (it != s0.end())
- {
- cout << *it << " ";
- ++it;
- }
- cout << endl;
it 是迭代器的对象,迭代器里面都有begin和end,分别表示第一个元素和最后一个的下一个元素。
这是正向迭代器,还有反向迭代器:
- string::reverse_iterator rit = s0.rbegin();
- while (rit != s0.rend())
- {
- *rit += 1;
- ++rit;
- }
- rit = s0.rbegin();
- while (rit != s0.rend())
- {
- cout << *rit << " ";
- ++rit;
- }
- cout << endl;
与正向相对,反向开始是rbegin,结束是rend,它是倒着遍历的。
看到迭代器的示例,有人会问 “这迭代器看上去非常麻烦,不好理解而且难记,不如直接用下标访问的方式 ”
————下标访问的方式在string和vector(顺序表)中可以使用,但是在其他容器(如map)就无法使用了。而迭代器是一种容器通用的遍历方式,具有普遍性。
迭代器还有const修饰类型的,上面讲的迭代器对数据可读可写,const修饰的是只读属性,像print这种接口就要写成const修饰的。
- void print(const string& s)
- {
- string::const_iterator it = s.begin();
- while (it != s.end())
- {
- cout << *it << " ";
- ++it;
- }
- cout << endl;
- }
- int main()
- {
- string s0("abcd");
- print(s0);
- return 0;
- }
string::const_iterator it = s.begin(); 这里要用const修饰迭代器对象,防止修改迭代器里的内容(*it)注意:这里不能写成 const string::iterator it = s.begin(); 这种是防止修改 it本身,而我们要遍历是需要修改 it 的,而 it 指向的内容不能修改。
const修饰的迭代器有正向的,也就有反向的。
- void Test1()
- {
- string s0 = "qwer";
- string::const_reverse_iterator rit = s0.rbegin();
- while (rit != s0.rend())
- {
- cout << *rit << " ";
- ++rit;
- }
- cout << endl;
- }
看上去确实长了点,但是有的时候是不可避免的,只要意思表达清楚即可,何况库里面也是这么使用的。
总结:正向、反向迭代器可以读取和修改容器数据,而const正向、反向迭代器可以读取容器数据。
那么什么时候需要const版本,什么时候需要非const版本呢?
1、只读功能函数,只需要const版本;
2、只写功能函数,只需要非const版本;
3、可读可写功能函数,两个都需要。
可读可写功能的函数,因为有可能是只读对象调用它,也可能是可读可写对象调用它,而const修饰的只读的对象只能调用const版本的函数, 只写的 \ 可读可写的对象可以不需要const版本的函数,因此需要提供两个版本。