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类的增删查改的模拟实现,那些才是比较重要的部分,理解起来也比较难,所以下一节需要重点关注,喜欢的可以一键三连哦!

相关推荐
Bl_a_ck14 分钟前
开发环境(Development Environment)
开发语言·前端·javascript·typescript·ecmascript
UpUpUp……24 分钟前
Linux--JsonCpp
linux·运维·服务器·c++·笔记·json
每天一个秃顶小技巧33 分钟前
02.Golang 切片(slice)源码分析(一、定义与基础操作实现)
开发语言·后端·python·golang
工藤新一¹1 小时前
蓝桥杯算法题 -蛇形矩阵(方向向量)
c++·算法·矩阵·蓝桥杯·方向向量
serve the people2 小时前
解决osx-arm64平台上conda默认源没有提供 python=3.7 的官方编译版本的问题
开发语言·python·conda
柒七爱吃麻辣烫2 小时前
在Linux中安装JDK并且搭建Java环境
java·linux·开发语言
fallzzzzz2 小时前
C++ stl中的list的相关函数用法
c++·list
极小狐3 小时前
如何构建容器镜像并将其推送到极狐GitLab容器镜像库?
开发语言·数据库·机器学习·gitlab·ruby
多多*3 小时前
Java反射 八股版
java·开发语言·hive·python·sql·log4j·mybatis
正在走向自律3 小时前
从0到1:Python机器学习实战全攻略(8/10)
开发语言·python·机器学习