int main()
{
string s1("hello world");//带参构造
string s2;//无参构造
string s3(5, 'x');
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
return 0;
}
string(const char* str = "")
: _str(new char[strlen(str) + 1])
, _size(strlen(str))
, _capacity(_size)
{
memcpy(_str, str, _size + 1);
}
拷贝构造实现的是深拷贝,会再开辟一段新的空间。如果不是深拷贝,则会使同一块空间调用两次析构函数。发生错误!
int main()
{
string s1("hello world");//带参构造
string s2(s1);//拷贝构造
cout << s1 << endl;
cout << s2 << endl;
return 0;
}
//传统写法
string(const string& str)
{
_str = new char[str._capacity + 1];
memcpy(_str, str._str, str._capacity + 1);
_size = str._size;
_capacity = str._capacity;
}
以上拷贝构造是传统写法,尽量使用传统写法,因为现代写法会有硬伤,如果要拷贝的字符串是hello\0world,那么只会拷贝hello,遇到\0就结束。
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
int main()
{
string s1("hello");//带参构造
cout << s1.size() << endl;
return 0;
}
size是有效是否的个数,不包括\0
为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小。(只大不小)
resize(n) 改变字符串size,将字符串中的有效字符个数改变到n个,当字符个数增多时,用0来填充多出的元素空间。如果将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
int main()
{
string s1("hello world");//带参构造
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
return 0;
}
重载[],类似于下标的方式来索引元素。
通过迭代器来遍历string,begin获取第一个字符的迭代器,end获取最后一个字符下一个位置的迭代器。
int main()
{
string s1("hello world");//带参构造
//string::iterator it = s1.begin();
auto it = s1.begin();//auto自动类型识别
while (it != s1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
return 0;
}
范围for底层就是迭代器
int main()
{
string s1("hello world");//带参构造
for (auto ch : s1)
{
cout << ch << " ";
}
cout << endl;
return 0;
}
在字符串后尾插字符
int main()
{
string s1("hello world");//带参构造
cout << s1 << endl;
s1.push_back('x');
cout << s1 << endl;
return 0;
}
在字符串后追加一个字符串
int main()
{
string s1("hello world");//带参构造
cout << s1 << endl;
s1.append("xxxxxxxxxxxxxxxxxx");
cout << s1 << endl;
return 0;
}
即可以+=字符,又可以+=字符串,底层实现了string& operator+=(cosnt char ch)和string& operator+=(cosnt char* str)的重载。
int main()
{
string s1("hello world");//带参构造
cout << s1 << endl;
s1 += 'x';
cout << s1 << endl;
s1 += "yyyyyyyyyyyyyyy";
cout << s1 << endl;
return 0;
}
返回的是char* 的字符串,为了兼容C语言。底层实现const char* c_str() const;
int main()
{
string s1("hello world");//带参构造
cout << s1.c_str() << endl;
cout << s1 << endl;
return 0;
}
int main()
{
string s1("hello world");//带参构造
cout << s1.find('w') << endl;
cout << s1.find('l', 5) << endl;
cout << s1.find("wor") << endl;
return 0;
}
int main()
{
string s1("hello world");//带参构造
cout << s1.substr(5, 3) << endl;
return 0;
}
//流提取
istream& operator>>(istream& in, string& str)
{
str.clear();
char ch = in.get();
//读取出前面的空格或换行字符
while (ch == ' ' || ch == '\n')
{
ch = in.get();
}
while (ch != '\n')
{
str += ch;
ch = in.get();
}
return in;
}
输出到屏幕上,string输出是按size的大小输出,不是遇到\0结束。
//流插入
ostream& operator<<(ostream& out, const string& str)
{
for (auto ch : str)
{
out << ch;
}
return out;
}
说明:上述String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。
//传统写法——赋值元素符重载
String& operator=(const String& s)
{
if (this != &s)
{
char* pStr = new char[strlen(s._str) + 1];
strcpy(pStr, s._str);
delete[] _str;
_str = pStr;
}
return *this;
}
//现代写法——赋值元素符重载
string& operator=(string tmp)
{
swap(tmp);
return *this;
}
调用拷贝构造创建tmp,将tmp和*this交换,出作用域调用tmp的析构函数。