目录

0.初始化成员变量
1.构造函数
2.拷贝构造函数
3.赋值重载
4.下标操作符重载
5.输出重载
6.析构函数
7.swap

0.初始化成员变量

在string里面需要有一个char指针来存储string的地址,两个整形变量存储最大可存储字符数和当前已存储字符数,用size_t类型是提高代码的可移植性。

1
2
3
4
5
6
7
class string 
{
private:
char* _str;
size_t _size;
size_t _capacity;
}

1.构造函数

在标准环境下我们定义string类型变量时一般都是

1
2
3
4
string s0;
string s1("hello world");
string s2="hello world";
string s3(&s1);

先来实现s0和s1的方法。在s0的定义方法中,s0是未被初始化的,这会产生很多问题,如在后续定义_size和_capacity时会报错,strlen不能传入空指针,此时需要在前面给出一个默认值””。所以在编程中,即使没有赋予s0初始值,但C++依然会给出其默认值””。

1
2
3
4
string(const char* str = "") :_size(strlen(str)), _capacity(_size) {
_str = new char[_capacity + 1];//+1给'/0'留个位置
strcpy(_str, str);
}

2.拷贝构造函数

同构造函数差不多,只是传入了一个string参数

1
2
3
4
5
string(const string& s):_size(s._size),_capacity(s._capacity)
{
_str = new char[_capacity + 1];
strcpy(_str, s._str);
}

3.赋值重载

首先赋值前先判断传入的参数是否是自身,是则返回,因为赋值操作需要删除原本的_str,但同时又要访问原来的地址会出现错误。
tmp的申请操作必须在delete之前,因为可能出现申请不到空间的错误,如果已经delete,但又没有申请到空间就会崩溃了。

1
2
3
4
5
6
7
8
9
10
11
12
13
string& operator=(const string& s) {
if (this != &s)
{
char* tmp = new char[_capacity + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;

}
return *this;
}

4.下标操作符重载

重载下标操作符,提供了只读和可写两种访问方式(一开始我以为只有一种,因为只读的访问真的没怎么用过,看了看源码发现这个[]竟然还有重载)。其中引入assert.h中的assert宏定义在程序越界的时候报错中断程序。

1
2
3
4
5
6
7
8
9
10

char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const {
assert(pos < _size);
return _str[pos];
}

5.输出重载

用友元函数重载<<,把str放入IO流中

1
2
3
4
friend std::ostream& operator<<(std::ostream& os, const string& str) {
os << str._str;
return os;
}

6.析构函数

释放_str的对象空间,同时把_str赋值nullptr,防止其变成野指针。

1
2
3
4
5
~string() {
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}

7.swap

1
2
3
4
5
6
void swap(string& s)
{
std::swap(_str, s._str);//请注意_str是否有非空值
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}

要断网了先写到这,明天再写,还有swap和页内跳转没弄

date: 2023-03-21 23:16:16
tags: