引言
上一篇文章已经对string类进行了简单的介绍,大家只要能够正常使用即可。
这篇文章主要是对string类的几个重点的基本接口函数进行模拟实现,分别有string类的构造,拷贝构造,赋值运算符重载,析构函数,以及交换函数。而这几个函数的模拟也有可能出现在面试中。
一,传统写法
//定义一个叫做bit的命名空间,隔离C++库里的string类
namespace bit
{
class string
{
public:
//有参与无参构造用全缺省进行合并,在声明处给缺省值
string(const char* str = "")//传参构造
:_size(strlen(str))
{
//为了避免多次strlen计算,并且符合声明的顺序
//只把_size放在初始化列表,其余放在函数体中
_str = new char[_size + 1];//多开一个是给\0的
_capacity = _size;
strcpy(_str, str);//把初始化内容拷贝进空间
}
//要用深拷贝进行拷贝构造
//s2(s1);把s1拷贝给s2,*this是s2,s是s1的别名
string(const string& s)
{
//开一个和要拷贝的一样大小的空间
_str = new char[s._capacity + 1];
strcpy(_str, s._str);//把数据拷贝进新空间
_size = s._size;
_capacity = s._capacity;
}
//赋值运算重载
//s1 = s3;//s1是*this,s是s3的别名
string& operator=(const string& s)
{
//避免自己给自己赋值
if (this != &s)
{
//开新空间,拷贝数据,释放原空间,改变指针指向
char* tmp = new char[s._capacity + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
return *this;
}
}
const char* c_str() const
{
return _str;//返回字符串的首地址,用于打印数据
}
//交换函数
//s1.swap(s3)
//注意:这里传参要传引用,避免传值传参发生拷贝构造,语法上造成无穷递归
void swap(string& s)
{
//调用库中的swap函数,交换内置类型
//不直接交换数据,而是交换两块空间的指针
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
~string()
{
delete[] _str;//析构销毁资源
_str = nullptr;//置空
_size = _capacity = 0;//置0
}
private:
char* _str;
size_t _size;//有效数据个数,指向最后一个有效数据的下一个位置\0
size_t _capacity;//容量
};
}
二,现代写法
现代写法上的差异主要是拷贝构造,赋值拷贝发生了变化,在这里效率上并没有提高多少,但是这种写法不仅适用于string类,后面的链表,树也同样适用。因为链表,树等要拷贝节点,不容易进行深拷贝。
namespace bit
{
class string
{
public:
//构造函数
string(const char* str)
:_size(strlen(str))
{
_str = new char[_size + 1];
_capacity = _size;
strcpy(_str, str);
}
//拷贝构造
//s2(s1)
//s是s1,*this是s2
string(const string& s)
{
//复用构造函数,构造一个tmp,再用tmp对象和this交换
//如果不在声明时给缺省值,刚开始s2是随机值,tmp和s2交换后
//tmp就是随机值,tmp出了函数会调用析构函数,此时程序可能会崩溃
//所以最好给缺省值
string tmp(s._str);
//显式调用swap函数
//this->swap(tmp);
swap(tmp);
}
//赋值运算符重载
//s3 = s1
//s1是s,s3是*this
/*string& operator=(const string& s)
{
if (this != &s)
{
string tmp(s._str);
swap(tmp);
}
return *this;
}*/
//s3 = s1 这里的传参不能用引用
//传值传参会进行拷贝构造,s1会拷贝一份给tmp
//再让tmp与s3交换
string& operator=(string tmp)
{
swap(tmp);//一行代码实现赋值重载
return *this;
}
const char* c_str()const
{
return _str;
}
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
//析构函数
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
private:
char* _str = nullptr;
size_t _size = 0;
size_t _capacity = 0;
};
}