string类是C++的一个常见的面试题,考查面试者的基本功,虽然简单,但是有很多细节需要注意。
#pragma once
#include <assert.h>
/*
深拷贝与浅拷贝:
浅拷贝,只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,
而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。浅拷贝是指源对象
与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。
深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。
举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿
还是李四缺胳膊少腿都不会影响另外一个人。
*/
class String
{
friend ostream& operator<<(ostream& _cout, const String& s);
public:
/*
String()
:_pStr(/ *new char('\0')* /new char[1])
{
_pStr[0] = '\0'; //不能是"\0"
}
//new和delete,new[]和delete[]一定要匹配使用
//strlen 不能传NULL
String(char* pStr)
:_pStr(new char[strlen(pStr)+1])
{
strcpy(_pStr, pStr); //strcpy会拷贝'\0'过去
}
*/
//构造函数合并
String(char* pStr = "")
{
_size = strlen(pStr);
_capacity = _size+1;
_pStr = new char[_size+1];
strcpy(_pStr, pStr);
}
/*
//拷贝构造函数常规写法
String(const String& s)
:_pStr(new char[strlen(s._pStr)+1])
{
strcpy(_pStr, s._pStr);
}
*/
String(const String& s)
:_pStr(NULL) //需要先将this->_pStr置为空,否则交换后tmp为随机值,析构tmp时delete[]出现错误
{
String tmp(s._pStr);
std::swap(_pStr, tmp._pStr);
}
/*
//赋值运算符重载常规写法 -> 释放原来的空间,开辟和s一样大的空间
String& operator=(const String& s)
{
if (this != &s)
{
/ *
//存在一致性问题。如果new空间失败,原来的空间将被释放,深拷贝失败
delete[] _pStr;
_str = new char[strlen(s._pStr)+1];
strcpy(_pStr, s._pStr);
* /
//先开辟空间,再拷贝
char* tmp = new char[strlen(s._pStr)+1];
strcpy(tmp, s._pStr);
delete[] _pStr;
_pStr = tmp;
}
return *this;
}
*/
/*
//赋值运算符重载现代写法
String& operator=(const String& s)
{
if (this != &s)
{
String tmp(s._pStr);
std::swap(_pStr, tmp._pStr);
}
return *this;
}
*/
//赋值运算符重载现代写法
String& operator=(String s)
{
swap(_pStr, s._pStr);
return *this;
}
~String()
{
if (_pStr)
delete[] _pStr;
}
char* C_Str()
{
return _pStr;
}
char& operator[](size_t index)
{
return _pStr[index];
}
void PushBack(const char& ch)
{
/*_CheckCapacity(_size + 2);
_pStr[_size] = ch;
_pStr[++_size] = '\0';*/
Insert(_size, ch);
}
void PopBack()
{
assert(_size > 0);
--_size;
_pStr[_size] = '\0';
}
void Insert(size_t pos, char ch)
{
assert(pos <= _size);
_CheckCapacity(_size + 2);
size_t cur = _size;
while (cur >= pos)
{
_pStr[cur+1] = _pStr[cur];
cur--;
}
_pStr[pos] = ch;
++_size;
}
void Insert(int pos, const char* str)
{
assert(pos>=0 && pos <= _size);
//增容
size_t size = strlen(str);
_CheckCapacity(_size+1+size);
//挪动数据
int index = _size;
while (index >= pos)
{
_pStr[index+size] = _pStr[index];
--index;
}
//拷贝
for (size_t i = 0; i < size; ++i)
{
_pStr[pos++] = str[i];
}
_size += size;
}
int Find(char ch)
{
for (size_t index = 0; index < _size; ++index)
{
if (_pStr[index] = ch)
{
return index;
}
}
return -1;
}
int Find(const char* subStr)
{
assert(subStr);
size_t dstIndex = 0; //要查找的子串
size_t srcIndex = 0;
size_t subSize = strlen(subStr);
for (dstIndex = 0; dstIndex <= _size - subSize; ++dstIndex)
{
for (srcIndex = 0; srcIndex < subSize; ++srcIndex)
{
if (subStr[srcIndex] != _pStr[dstIndex+srcIndex])
{
break;
}
}
if (srcIndex == subSize)
{
return dstIndex;
}
}
return -1;
}
void Erase(size_t pos)
{
assert(pos < _size);
for (size_t i = pos+1; i <= _size; ++i)
{
_pStr[i-1] = _pStr[i];
}
--_size;
}
String& operator+=(const String& s)
{
Insert(_size, s._pStr);
return *this;
}
//String s("Hello");
//可以使用 s += String(" World"); String(" World") -> 拷贝构造 -> String& s
//也可使用 s += " World"; " World" -> 构造函数 -> String& s
//如果改为String& operator+=(String& s)则不能使用 s += " World"。 例如:
/*
int i = 0;
//double& a = i; //i先创建一个临时对象,然后把临时对象给double& a,a就成为一个临时变量的引用。错误
const double& a = i; //加const,可以引用临时变量。正确
*/
/*
String s1 = "sssssss"; //"sssssss"生成一个匿名对象,匿名对象再构造s1。编译器将两步优化为一步:"sssssss"直接构造s1。
//String& s2 = "sssssss"; //不能引用匿名(临时)对象。错误
const String& s3 = "sssssss"; //加const,可以引用临时变量。正确
*/
bool operator==(const String& s)
{
return (strcmp(_pStr, s._pStr) == 0);
}
bool operator>(const String& s)
{
return (strcmp(_pStr, s._pStr) > 0);
}
bool operator>=(const String& s)
{
return (*this > s || *this == s);
}
bool operator<(const String& s)
{
return !(*this >= s);
}
bool operator<=(const String& s)
{
return !(*this > s);
}
protected:
void _CheckCapacity(size_t needSize)
{
if (_size+1 >= _capacity)
{
_capacity = _capacity+needSize > 2*_capacity ? needSize : 2*_capacity;
_pStr = (char*)realloc(_pStr, _capacity);
}
}
protected:
char* _pStr;
size_t _size;
size_t _capacity;
};
ostream& operator<<(ostream& _cout, const String& s)
{
_cout<<s._pStr;
return _cout;
}
推荐文章:
C++面试中string类的一种正确写法:http://coolshell.cn/articles/10478.html
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。