C++初阶-string类的模拟实现1

目录

​编辑

1.模拟实现string类的原因

2.string类模拟实现注意的点

[3.string::string(const char* s)的模拟实现](#3.string::string(const char* s)的模拟实现)

3.1初始版本

3.2进阶版本

3.3最终版本

4.string::c_str()的模拟实现

5.string::string()的模拟实现

5.1初始版本

5.2最终版本

6.string::~string()的模拟实现

7.总结


1.模拟实现string类的原因

在面试中,面试官总喜欢让学生自己来模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。而且我们之后需要用到string类的地方还是比较多的,所以这里就相当于更加深入的了解它如何实现的了,总之是有益无害的!

2.string类模拟实现注意的点

在模拟实现时,我们需要学习一部分底层,只是把比较重要的函数实现了其他不重要的函数就不做过多讲解了,函数实现的时候可能顺序并不是按照C++官网的分类来的了。

由于string类可能会有命名冲突问题,我们需要把string类的模拟实现和测试函数都放到一个命名空间里面,而且我们可能不能把这个std的命名空间展开,之后我们需要比较二者的不同之处的。

cpp 复制代码
//.h文件
namespace td
{
	class string
	{
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};
}

这是基本结构了(少了npos和之前额外补充的buff,之后我们都会围绕这个结构来进行讲解,当然这个是放到.h文件中的,因为之后我们实现的时候也需要放到两个不同的文件中,所以可能需要声明在.h文件中,而定义在.cpp文件中,但是有些比较短小的函数我们可以在.h文件中定义,使它成为内联函数。

3.string::string(const char* s)的模拟实现

3.1初始版本

我们用初始化列表来进行初始化,并且我们需要用strlen函数来计算它的字符个数。由于还要申请空间,所以我们还需要用new函数来申请内存空间,并把所有的数据拷贝到_str里面去,所以得到了这个:

cpp 复制代码
//.h
#include<string.h>
namespace td
{
	class string
	{
	public:
		string(const char* str = " ");
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};
}
cpp 复制代码
//.cpp
#include"test.h"
#define _CRT_SECURE_NO_WARNINGS 1
namespace td
{
   string::string(const char* str)
	   :_str(new char[strlen(str)+1])
	   ,_size(strlen(str))
	   ,_capacity(strlen(str))
   {
      strcpy(_str, str);
   }
}

如果按照声明顺序进行初始化的情况下,那么这个代码是没有任何问题的,但是这样写起来很麻烦,因为总是用strlen(str)函数,我们知道这个函数的时间复杂度是O(n)的,很影响效率,所以我们要用_size或者_capacity进行初始化。

3.2进阶版本

在.h文件中_size要在第一个位置声明,其他的随意,则:

cpp 复制代码
//.cpp
#include"test.h"
#define _CRT_SECURE_NO_WARNINGS 1
namespace td
{
   string::string(const char* str)
	   :_str(new char[_size+1])
	   ,_size(strlen(str))
	   ,_capacity(_size)
   {
    strcpy(_str, str);
   }
}

但是这样的方式会有问题:

所以我们如果这样写就会导致这个运行出错,至于原因可能是声明的顺序必须是开始的顺序那样,但是那样会导致在_str定义时,而_size未初始化,可能会导致用这个函数时崩溃(因为随机值的话如果空间没有开够,就会越界)。那么如何解决呢?

3.3最终版本

cpp 复制代码
//.cpp
   string::string(const char* str)
	   :_size(strlen(str))
   {
	   _capacity = _size;
	   _str = new char[_size + 1];
	   strcpy(_str, str);
   }

我们可以声明的时候和开始版本一样,但是我们不在初始化列表里面初始化,我们直接在函数体里面初始化,这样就不会报错了。之前我们是建议在初始化列表初始化,但是这只是一个建议,我们在函数体内初始化一些就不会有这么多事情了!

4.string::c_str()的模拟实现

这个比较简单,我们直接在那个.h文件中实现这个函数就可以了:

cpp 复制代码
//.h
const char* c_str() const
{
	return _str;
}

5.string::string()的模拟实现

5.1初始版本

cpp 复制代码
//.cpp
   string::string()
	   :_str(nullptr)
	   ,_size(0)
	   ,_capacity(0)
   {

   }

我们需要把之前的那个默认构造函数注释掉,因为不能有多个默认构造函数(在using namespace std的情况下),然后测试如下代码:

cpp 复制代码
//.cpp
   void  test1() 
   {
	   string s2;
	   cout << s2.c_str() << endl;
   }

这个不是放在成员函数里面的,而是只在命名空间td里面的,因为如果用在主函数里面那么就还要那个指定命名空间,所以这样更好一些,则运行结果为:

这样是因为它崩溃了。

为什么会出现这种情况?

cout打印char*的时候比较特殊,因为char*被认为是字符串,所以这样打印出来的结果不是指针类型,而是按字符串打印。但是这样打印就会直接对char*的指针进行解引用,直到遇到'\0',但我们在实例化对象时,这个是空指针(_str),空指针解引用会崩溃。

但是如果我们改为如下形式:

cpp 复制代码
//.cpp
void test1()
{
 std::string s2;
 cout << s2.std::string::c_str() << endl;
}

那么运行结果如下:

我们发现如果用库里面的函数就不会崩溃,之前我们如果不指定类域默认用的是本类域里面的函数,所以会崩溃。因为库里面不是用nullptr去初始化_str,而是开了一个字符大小的空间(一个字节)。

5.2最终版本

cpp 复制代码
//.cpp
string::string()
 :_str(new char[1]{'\0'})
 ,_size(0)
 ,_capacity(0)
{

}

那么运行结果如下:

当然这是在已经写了析构函数的情况下运行的结果,之前都没有写析构函数,所以运行出来就会报错。

6.string::~string()的模拟实现

这个函数很简单,只要先释放内存后再把_str置为nullptr且_size,_capacity都置为0即可,代码如下:

cpp 复制代码
//.cpp
string::~string()
{
 delete[] _str;
 _str = nullptr;
 _size = _capacity = 0;
}

用之前的测试代码,调试有:

运行结果是没有问题的。

但是之后我会把这个string()的构造函数直接删掉,因为之后用的也不多,就用const char*的即可。

7.总结

这里就先把那些比较重要的构造函数(除拷贝构造外)已经讲了,下一节将进行讲解:string类的增删查改的模拟实现,那些才是比较重要的部分,理解起来也比较难,所以下一节需要重点关注,喜欢的可以一键三连哦!

相关推荐
chushiyunen8 分钟前
python中的@Property和@Setter
java·开发语言·python
小樱花的樱花15 分钟前
C++ new和delete用法详解
linux·开发语言·c++
froginwe1116 分钟前
C 运算符
开发语言
fengfuyao9851 小时前
低数据极限下模型预测控制的非线性动力学的稀疏识别 MATLAB实现
开发语言·matlab
摇滚侠1 小时前
搭建前端开发环境 安装 nodejs 设置淘宝镜像 最简化最标准版本 不使用 NVM NVM 高版本无法安装低版本 nodejs
java·开发语言·node.js
t198751281 小时前
MATLAB十字路口车辆通行情况模拟系统
开发语言·matlab
yyk的萌1 小时前
AI 应用开发工程师基础学习计划
开发语言·python·学习·ai·lua
Amumu121382 小时前
Js:正则表达式(一)
开发语言·javascript·正则表达式
努力的章鱼bro2 小时前
操作系统-FileSystem
c++·操作系统·risc-v·filesystem
96772 小时前
cURL curl
c++