当前位置: 首页 > news >正文

c++ string类的模拟实现的注意事项

一.构造函数

第一种形式,使用字符指针赋值

为了防止修改,我们传入了常量字符串。但是这里的初始化列表出错了,因为_str是一个变量,将常量给到一个变量涉及到权限的放大,是错误的。那该怎么写呢?对_str的赋值只能使用strcpy字符串拷贝,如下:

这样对了吗??还是不对!!!因为_str没有开辟空间!!!!

体现了初始化列表与函数的结合

但是,main函数中创建一个字符串对象却出错了!!!!

为什么呢?注意初始化列表的顺序!!!!!是按照变量定义的顺序进行的!!!然而_str是最先定义的,所以在执行_str(new char[_chpacity+1]时,_capacity还是随机值(或者是vs下的0),所以就会出错!!!。所以,对_str的空间的开辟最好定义在函数体内,如下:

二.头文件包含问题以及预处理文件的查看

上面我们在写mystring.h的时候没有包含任何头文件,但为什么strcpy能够使用,能够编译运行通过呢?

这是因为,十以上如处理后的文件是将main所在文件中包含的头文件都展开了,也就是将iostream、string、std、mystring.h依次展开,所以当mystring.h中用到strcpy时,他就会主动去上面寻找定义。这可以根据预处理的文件证明。如下为查看预处理文件的方式:

右键项目-属性-c\c++-预处理器,进行如下修改:

找到要查看的文件的预处理文件,进行编译:

打开被编译文件所在文件夹:

找到debug文件夹:

进入debug文件夹并打开test1.i文件:

就可以看到了:

在main函数之上都是头文件的展开,包括了库里的头文件以及我们自己写的头文件。

注意,看完了记住将是改成否!!!

但注意,如果mystring.h的包含实在std上面的话,有些std中的东西在mystring.h中就用不了了,比如cout。

三.c_str

注意,返回值是常量指针类型。

四.无参构造

能否再写个如下的无参构造?

不可以,这样的话,c_str可能会崩掉。

那怎么写最好呢?只写一个构造函数,并且是全缺省的,如下:

五.赋值重载

如果没有重写赋值函数,就会出现下面的情况:

进行了浅拷贝,s和s2指向了同一块空间。所以要重写赋值重载函数:

六.operator[]

两个版本,可读可写。

七.迭代器

然后再写个const形式的:

这样对吗?显然不对

为什么呢?因为const iterator其实是等价于char* const,也就是说表示指针是一个常量的,他的指向不能修改,但是,他指向的空间的内容可以修改!!!,那就没有防止修改的意义了。应该如下修改

这样就会发现,const字符串调用了begin后,生成的迭代器不能给到一个变量,而只能给到一个常量迭代器。,这样,const字符串就不能被修改了。

八.push_back

if里面的内容其实就是reserve预留空间这个函数,所以我们可以封装起来:

但注意细节,将tmp给到_str前,要释放原来的空间:注意是显示放再赋值

还有一个错误:尾插后要让size加一,并且要在尾部添加‘\0'。,最后如下:

九.append

注意最后一个字符置为0,以防传参时仅仅传入一个字符的地址!!!

十.insert

这样写有一个弊端:向后移动的时候,字符串末尾的'\0'被覆盖了!!!怎么办??一种方式是在插入完毕后再规定_size位置为\0,还有一种方法是从第_size位置开始移动,也就是连着末尾的\0一起移动,如下:

这段代码还有要注意的地方:如果移动的代码是像下面一样写的,那么当头插的时候,由于i是size_t类型,i减到最后本应是-1,但是编译器认为这是无符号整型,是一个非常大的数,就会导致无限循环:

一定要注意细节。

十一.流插入重载

第一种方式,写成友元函数。但要注意,友元函数必须和对应的类写在一个命名空间中!!!!否则依然无法访问类中的私有成员,如下:

但其实,这里的流插入不需要访问类内部的私有成员,所以不是非得写成友元函数,也可以在明明空间外面这样写:

注意,参数有误,写到命名空间外面后,就要在string前面加上命名空间的名字,如下:

注意,这里的auto其实就是转成了迭代器的调用。那么它调用的是const迭代器还是非const迭代器呢?如下可以证明

调用的是常量迭代器

十二.流提取重载

注意,有个问题,cin会自动跳过空格,去获取下一个字符。这怎么办??

cin是istream类型的对象,其中有一个成员函数get,它可以拿到所有的字符

还有一个问题,输入流是要把s的内容全部改了,但是加等就是简简单单的追加。所以在操作之前要将s清空。如下加上这个clear函数:

但是这个流提取的写法还不够好,它得一直扩容。

解决方法一:使用reserve预留空间。但是,不知道需要多大,太大了浪费

解法二:使用一个字符数组:

十三.erase

这其实只是一个最主要步骤。但是还有其他的。首先,npos是自定义的,要定义成成员变量,为了防止修改,将他定义成const的,同时,npos应该是所有成员共享的,所以定义成static的。static成员要在类外初始化

其次,还要考虑pos+len>size的情况

最后,别忘记更新_size的值。

十四.拷贝构造

开辟一个一样大的空间,将数据拷贝过去。

深拷贝到本质:不能任由指针成员进行拷贝,但我们可以考虑让别人做

也可以封装成函数,注意命名空间

十五.回看赋值重载

可以调用reserve来开辟空间。

但也可以用到swap,借他人之手来进行

这种现代写法有个好处,原先自己的空间不用去主动释放,而是交换给了tmp,让tmp去释放。

最极致的现代写法:

直接交换s,但注意,一定要改成string变量,而不能使用const引用了

http://www.lryc.cn/news/432917.html

相关文章:

  • Unity3D中控制3D场景中游戏对象显示层级的详解
  • 代码执行漏洞-Log4j2漏洞 vulhub CVE-2021-44228
  • uniapp / uniapp x UI 组件库推荐大全
  • 花8000元去培训机构学习网络安全值得吗,学成后就业前景如何?
  • PhpStorm 下调试功能配置
  • MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)
  • 【H2O2|全栈】关于HTML(4)HTML基础(三)
  • 关于找不到插件 ‘org.springframework.boot:spring-boot-maven-plugin:‘的解决方案
  • 深入RabbitMQ世界:探索3种队列、4种交换机、7大工作模式及常见概念
  • 将目标检测模型导出到C++|RT-DETR、YOLO-NAS、YOLOv10、YOLOv9、YOLOv8
  • 【Windows】解决新版 Edge 浏览器开机自启问题(简单有效)
  • 如何给3D人物换衣服CC4
  • 如何对列表、字符串进行分组
  • 【GEE代码实例教程详解:NDVI时间序列趋势分析】
  • 51单片机-DS1302(RTC实时时钟芯片)
  • FreeRTOS学习笔记—②RTOS的认识及任务管理篇
  • 【C++从练气到飞升】22---C++中的异常
  • 前端:HTML、CSS、JS、Vue
  • RocksDB简介
  • [VC] Visual Studio中读写权限冲突
  • ChatGPT3.5/4.0新手使用手册,国内中文版使用教程
  • 基于MicroPython的ESP8266与超声波传感器设计方案
  • 仿华为车机UI--图标从Workspace拖动到Hotseat同时保留图标在原来位置
  • C++ 中的 override 和 overload的区别
  • spring boot3框架@Validated失效
  • UE5引擎工具链知识点
  • Python的图像算术与逻辑运算详解
  • WSL 下的 CentOS 装 Docker
  • v0.dev快速开发
  • python之字符串