如何初始化类的对象是由类本身决定的。一个类可以定义很多种构造函数。当然每种构造函数在在初始值得数量或者类型都有差别(函数重载)。
string() 构造空的string类对象,即空字符串 string(const char* s) 用C-string来构造string类对象 string(size_t n, char c) string类对象中包含n个字符c string(const string&s) 拷贝构造函
string s0;//默认初始化,s0是一个空字符串 string s1("hello world");//用字面值"hello world",构造s1 string s2(s1);//用s1拷贝构造 s2 string s3 = s2;//等价于s3(s2),用s2拷贝构造s3 //先用字面值"hello world"构造一个string类型的临时对象,再用临时对象拷贝构造s4. string s4 = "hello world"; string s5(10,'c');//将s5初始化为,由10个字符'c'组成的串(1)用IO操作符(<<,>>)读写string对象
我们可以使用标准库的iostream来读写int,double,等内置类型。也可以在string类里边通过运算符重载的方式,用IO操作符(<<,>>)读写string对象。
int main(){ string s; //空字符串 cin >> s;//将string 对象读入s遇到空白停止 cout << s << endl;//输出s retrun 0; }需要注意的是:在文件读取时,string类对象会忽略所有的空白(空格符,换行符,制表符等),从的一个真正的字符开始到空白结束。 所以程序输入的如果是" Hello world".输出的将会是"Hello"。
在运算符>> 和 << 重载时函数的返回值是运算符左侧的操作对象。所以所以多个输入或者输出可以连在一起:
int main(){ sting s1,s2;//定义两个空字符串 cin >> s1 >> s2;// 把第一个串读到s1中,第二个读到s2中 cout << s1 << s2 << endl;//输出 }如果这次依然输入" Hello world" 输出为“Helloword“ (2)使用getline读取一整行: istream& getline (istream& is, string& str); 有时候我们希望等在最终得到的字符串中,保留空白符。这时应该用getline函数代替>>运算符。函数从输入流is中读入内容到str中,直到遇到换行为止。geline只要一遇到换行符就结束读取操作并返回结果。如果一开始就输入换行符,那么就会得到一个空的sting对象。 getline也会返回他的流参数,因此可以使用getline的结果作为条件:
int main(){ string s0;//定义一个空串 //读入未知个string对象,每次读入一整行,直到文件的结束 while( getline(s0) ) cout<< s0 << endl; return 0; }size_t size() const;返回字符串有效字符长度。 size_t length() const;返回字符串有效字符长度 size_t capacity() const; 返回空间总大小 bool empty() const; 检测字符串释放为空串,是返回true,否则返回false void clear(); 清空有效字符 ,clear仅在逻辑层面进行数据清理,而不会进行内存释放。 void reserve (size_t n = 0);为字符串预留空间。 void resize (size_t n); void resize (size_t n, char c);将有效字符的个数该成n个,多出的空间用字符c填充 需要注意的是:
size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一 致,一般情况下基本都是用size()。
clear()只是将string中有效字符清空,不改变底层空间大小,只是将对象的_size置为0。
resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字 符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。操作后string对象有效元素的多少改变成了n。
reserve(size_t res_arg=0):为容器预留足够的空间,避免不必要的重复分配。不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,容器不会发生任何改变。如果大于将底层空间,则扩容。而对象有效元素的多少始终不发生改变。 关于size_t 和 size_type:
标准定义中,size_t和size_type被定义为unsigned int。但是sizt_t是C++的一个标准的typedef,全局有效,定义在全局名称空间中,size_type是STL定义的,size_t不是容器概念,而size_type是容器概念,没有容器不能使用。
size_t的引入增强了程序在不同平台上的可移植性。经测试发现,在32位系统中size_t是4字节的,而在64位系统中,size_t是8字节的,这样利用该类型可以增强程序的可移植性。
(1)使用范围for处理对象的每个字符;
c++11新标准提供了一种语句:范围for语句。这种语句遍历给定序列的每个元素
string str("Hello world"); for (auto a : str ) cout << c << endl;//输出当前字符,并换行范围for把变量a 和 序列 str联系起来。auto是让编译器确定a的类型,a的类型是char。每次循环将序列的下一个字符拷贝给变量a,然后输出。但是如果在范围for中修改str序列,上边变量的定义显然是不行的,因为每次循环都只是将str的字符拷贝一份给变量a。所以如果要改变序列str,就应该把循环变量定义成引用类型:
string str("Hello world"); for (auto &a : str ) a = 'H';//将str序列的每个字符换成'H' cout << str << endl;(2)用下标运算符[],处理string对象某个字符:
string s0 = "hello"; for(size_t i = 0; i < s0.size(); i++){ cout << s0[i]; } cout << endl;string对象的下标必须大于等于0,而小于s.size()。使用超出此范围的下标将引发不可预知的结果,以此推断,使用下标访问空string会引发不可预知的结果。 (3)用迭代器处理string对象的某个字符:
最常见的迭代器: string s = "hello"; string::iterator it = s.begin(); while( it != s.end() ){ cout<< *it <<" "; ++it; } cout << endl;需要注意的是,s.begin()是‘h’,但是s,end()是最后一个 字符’o’的下一个位置。
反向迭代器: string s = "hello"; string :: reverse_iterator it = s.rbegin(); while( it != s.rend() ){ cout<< *it <<" "; ++it; } cout << endl;程序会输出: o l l e h
const迭代器; const string s = "hello"; string :: const_iterator it = s.begin(); while( it != s.end() ){ cout<< *it <<" "; ++it; } cout << endl;(1)尾插一个字符 void push_back (char c);在字符串后尾插字符c (2)尾插一个字符串。 string& append (const string& str);//str的所有内容,拼接到对象的后边 string& append (const string& str, size_t subpos, size_t sublen);//str字符串从subpos开始共sublen位拼接到对象后边。 string& append (const char* s);//将c格式的字符串拼接到,对象的后边。 string& append (const char* s, size_t n);//字符串的前 n、位拼接到对象后边。 string& append (size_t n, char c);// 将5个字符c拼接到,对象后边。 (3)在字符串后追加字符串str string& operator+= (const string& str); string& operator+= (const char* s); string& operator+= (char c); (4)返回C格式字符串 const char* c_str() const noexcept; c_str()函数返回一个指向正规C字符串的指针常量, 内容与本string串相同。这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。 注意:一定要使用strcpy()函数 等来操作方法c_str()返回的指针 (5)从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 size_t find (const string& str, size_t pos = 0) const; //查找对象–string类对象 size_t find (const char* s, size_t pos = 0) const; //查找对象–字符串 size_t find (const char* s, size_t pos, size_t n) const; //查找对象–字符串的前n个字符 size_t find (char c, size_t pos = 0) const; //查找对象–字符 找到 – 返回 第一个字符的索引,没找到–返回 string::npos(代表 -1 表示不存在) (6)在str中从pos位置开始,截取n个字符,然后将其返回 string substr (size_t pos = 0, size_t len = npos) const;
(1)实现一个简单的string类包括 构造 拷贝构造 赋值运算符重载 析构 reserve(szie_t) push_back(char) 等
namespace LZH{ struct string{ string(char* str = ""){//构造 _size = strlen(str); _capacity = _size; _str = new char[_capacity + 1]; strcpy(_str, str);//strcpy 会连'\0' 一起拷贝 } void swap(string& s){ std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); } string(const string& s):_str(nullptr){//拷贝构造 string tem(s._str); swap(tem); } ~string(){//析构 delete[] _str; _str = nullptr; _size = _capacity = 0; } string& operator=(string s){//赋值运算符重载 先调用拷贝构造初始化形参 swap( s ); return *this; } void reserve(size_t newcapacity){ if (newcapacity <= _capacity){ return; } char* newstr = new char[newcapacity + 1]; strcpy(newstr, _str); delete[] _str; _capacity = newcapacity; _str = newstr; } void push_back(char c){ if (_size == _capacity){//扩容 int newcapacity = _capacity == 0 ? 1 : 2 * _capacity; reserve(newcapacity); } _str[_size++] = c; _str[_size] = '\0'; } private: size_t _size; size_t _capacity; char* _str; static size_t npos; }; size_t string :: npos = -1; }//namespace LZH(2)具体实现: https://github.com/WhynotHH/Simulate-STL/blob/master/string.h
