string模拟实现构造+析构
个人主页:Jason_from_China-CSDN博客
所属栏目:C++系统性学习_Jason_from_China的博客-CSDN博客
所属栏目:C++知识点的补充_Jason_from_China的博客-CSDN博客
string模拟实现构造
方案1(初始化列表的实现):
这一种方案是一种不完整方案,是不合适的方案,我是用来对比讲解使用的,所以可以看,可以不看,这里实现的无参数构造
//.h头文件 using namespace std;//突破域名 //这里我们采取namespace封装一下 namespace Test { class string { public: //构造函数 string(); string(const char* str); private: //这里本质上就是字符串的增删查改,所以和数据结构是有点像的 char* _str; size_t _size; size_t _capacity; }; }
初始化列表格式进行初始化:
- 其实对于构造函数我们之前学过初始化列表和函数体的两种方式,所以我们到底在实际操作的时候,使用哪一种方式?这里采取初始化列表讲解,分析利弊。
- 初始化列表进行初始化,带参数构造的使用会存在一点问题,就是,我们需要先计算出字符串长度,然后才能开辟空间
- 初始化列表的构造,是按照私有成员变量的顺序进行初始化的,所以在后期代码维护,你的代码别人不注意就会很容易更改从而导致错误
初始化列表两种方式的代码:
- 不带参数
这里创建是有一点小心机的,这里我们是_str(new char[]({'\0})->数组的形式创建空间,这里其实我们完全可以_str(new char{'\0}->不是数组形式创建空间,但是我们析构的时候,总不能再因为这个写两个析构函数吧,所以我这里直接就是使用创建多个空间的逻辑创建空间,也就是数组的形式创建空间- 带参数
方案2(函数体和初始化列表的综合实现):
- 上面我们已经发现,纯粹采取初始化列表是可以实现的,但是是存在一些问题的,也就是我们需要改变私有变量的顺序
- 初始化列表的构造,是按照私有成员变量的顺序进行初始化的,所以在后期代码维护,你的代码别人不注意就会很容易更改从而导致错误
- 所以我们可以采取更加符合常规的一种写法
这里解释一下namespace,命名空间不仅可以单独给,还可以直接大规模的给,这样我们就可以不用在string.cpp实现的文件里面每次实现接口都需要 Test::string::接口。
//.h头文件 using namespace std;//突破域名 //这里我们采取namespace封装一下 namespace Test { class string { public: //构造函数 string(const char* str=""); private: //这里本质上就是字符串的增删查改,所以和数据结构是有点像的 char* _str; size_t _size; size_t _capacity; }; }
//实现文件 #include"string.h" namespace Test { //构造函数(传参) string::string(const char* str) :_size(strlen(str)) { _capacity = _size; _str = new char[_size + 1]; strcpy(_str, str); // 目的地,来源 } }
代码的解释:
- 在头文件我们可以看见,string(const char* str="");,这里我们是不需要string(const char* str="\0");因为本身创建空间的时候就是会自带/0,没有必要继续加上/0
- 在实现上面,我们创建空间需要多创建一个空间,因为我们strlen是不计算\0的,所以我们需要_str = new char[_size + 1];从而在开辟空间的时候,多创建一个空间
- 最后我们只需要把字符拷贝到开辟好的空间,最后就可以
- 我们的测试我们会在实现析构之后一起进行测试,这里就不单独测试了
注意事项:
- 之前我们说过,在vs编译器下,cpp编译下,一些C语言的语法结构是需要写一行代码的,不然会导致报错
- #define _CRT_SECURE_NO_WARNINGS 1//这一行代码,这是编译器的行为,编译器也会提醒你加上,这里我说明一下,不是语法结构的问题,是编译器认为这里有危险,加上这一行强制使用就可以。
string模拟实现析构
析构函数的实现是比较简单的,这里只需要直接析构就可以,因为我们创建空间的时候我们都是采取数组的形式创建的空间,所以我们析构的时候,我们直接数组的形式析构就可以
//头文件 #define _CRT_SECURE_NO_WARNINGS 1 #pragma once using namespace std;//突破域名 //这里我们采取namespace封装一下 namespace Test { class string { public: //构造函数 string(const char* str=""); //析构函数 ~string(); private: //这里本质上就是字符串的增删查改,所以和数据结构是有点像的 char* _str; size_t _size; size_t _capacity; }; }
//实现文件 #include"string.h" namespace Test { 构造函数(不传参) //string::string() // :_str(new char[1] {'\0'}) // , _size(0) // , _capacity(0) //{} // _size指的是实际的个数 // _capacity指的是空间,空间的使用 //构造函数(传参) string::string(const char* str) :_size(strlen(str)) { _capacity = _size; _str = new char[_size + 1]; strcpy(_str, str); // 目的地,来源 } //析构函数 string::~string() { delete[] _str; _str = nullptr; _size = 0; _capacity = 0; } }
代码讲解:
- 首先我们析构_str字符串,这里我们采取析构数组的方式进行析构
- 让字符串指向空,C++的空和C语言的空是不一样的
- 最后把_size,_capacity,都归0
- 比较简单,这里不做过多赘述,这里的核心是提高测试调试的使用能力
代码测试:
- 在构造函数里面我们没有测试,因为一方面我们知道我们写的代码很简单不会报错,一方面我们的析构函数没有实现,其实不实现也可以测试,只是作者有点懒,想起来需要测试的时候,已经写到这里了。
- 构造函数的测试
- 析构函数的测试
注意事项:
- 下面我们讲解代码的时候,除非头文件有缺省参数参数,上代码的时候,我会只是实现这个函数接口的实现,但是需要头文件的时候,我会进行讲解这个头文件