《C++ string 完全指南:string的模拟实现》

string的模拟实现


文章目录

  • string的模拟实现
  • 一、浅拷贝和深拷贝
    • 1.浅拷贝
    • 2.深拷贝
    • 3.写时拷贝
  • 二、定义string的成员变量
  • 三、string的接口实现
    • 1.string的默认成员函数
      • (1)构造函数实现
      • (2)析构函数实现
      • (3)拷贝构造函数
      • (4)赋值运算符重载
    • 2.string的迭代器实现
    • 3.string的容量操作函数
    • 4.string的访问操作函数
    • 5.string的修改操作函数
    • 6.string的查找函数
    • 7.string的c_str和substr
    • 8.string的< <= > >= == !=
    • 9.string的operator>>
  • 四、源代码总结
    • 1.String.h
    • 2.String.cpp


一、浅拷贝和深拷贝

在这里插入图片描述


1.浅拷贝

在这里插入图片描述


2.深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出
一般情况都是按照 深拷贝 提供
在这里插入图片描述


3.写时拷贝

在这里插入图片描述


二、定义string的成员变量

在这里插入图片描述


三、string的接口实现

1.string的默认成员函数

(1)构造函数实现

这种短小频繁调用的函数,可以直接定义到类里面,默认是 inline
在这里插入图片描述


(2)析构函数实现

这里要注意一下判断 str是否为空
在这里插入图片描述


(3)拷贝构造函数

在这里插入图片描述
在这里插入图片描述


(4)赋值运算符重载

在这里插入图片描述


2.string的迭代器实现

string中迭代器iterator就是一个指针。所以我们直接使用typedef实现
begin()和end() 本质上都是 指针
在这里插入图片描述


3.string的容量操作函数

size()、capacity()、clear()、empty()都很简单!一看就懂!
在这里插入图片描述


接下来是reserve(),只要新容量大于旧容量就发生扩容。
在这里插入图片描述


在这里插入图片描述

在这里插入图片描述


4.string的访问操作函数

这部分较为简单,其实就是 数组的下表访问[ ]front()与back()
在这里插入图片描述


5.string的修改操作函数

两个常用的修改函数: push_back()与append()
在这里插入图片描述


+=就是在push_back和append的应用!
在这里插入图片描述


insert有两种类型,第一种类似于头插,第二种类似于任意位置插入
二者都需要挪动数据和检验数组的扩容问题


在这里插入图片描述

在这里插入图片描述


pop_back函数较为简单!
字符串的删除函数erase函数类似于尾删,也可以任意位置删除
将pos位置后所有字符往前移动len个单位,如果为字符len=1,否则len=字符串长度
在这里插入图片描述
在这里插入图片描述


6.string的查找函数

find函数既可以查找字符,也可以查找字符串(用strstr函数)
在这里插入图片描述

在这里插入图片描述


7.string的c_str和substr

在这里插入图片描述
在这里插入图片描述


8.string的< <= > >= == !=

在这里插入图片描述


9.string的operator>>

注意普通istream对象无法提前空格与\n。这是我们就需要一个函数get()来提取
在这里插入图片描述


四、源代码总结

1.String.h

代码如下(示例):

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<string>
#include<assert.h>
using namespace std;
namespace bit
{class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}/*string():_str(new char[1]{'\0'}),_size(0),_capacity(0){}*/// 短小频繁调用的函数,可以直接定义到类里面,默认是inlinestring(const char* str = ""){_size = strlen(str);// _capacity不包含\0_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}// 深拷贝问题// s2(s1)/*string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}*/void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}// s2(s1)// 现代写法string(const string& s){string tmp(s._str);swap(tmp);}// s2 = s1// s1 = s1/*string& operator=(const string& s){if (this != &s){delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}*/// s1 = s3;//string& operator=(const string& s)//{//	if (this != &s)//	{//		//string tmp(s._str);//		string tmp(s);//		swap(tmp);//	}//	return *this;//}// s1 = s3;string& operator=(string tmp){swap(tmp);return *this;}~string(){if (_str){delete[] _str;_str = nullptr;_size = _capacity = 0;}}const char* c_str() const{return _str;}void clear(){_str[0] = '\0';_size = 0;}bool empty() const{return _size == 0;}size_t size() const{return _size;}size_t capacity() const{return _capacity;}// 可读可写char& front(){return _str[0];}char& back(){return _str[_size - 1];}// 可读不可写const char& front()const{return _str[0];}const char& back()const{return _str[_size - 1];}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}/*void copy_on_write(){if (count > 1){深拷贝}}*/void reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void erase(size_t pos, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string substr(size_t pos = 0, size_t len = npos);private://char _buff[16];char* _str = nullptr;size_t _size = 0;size_t _capacity = 0;//static const size_t npos = -1;static const size_t npos;/*static const int N = 10;int buff[N];*/};bool operator<(const string& s1, const string& s2);bool operator<=(const string& s1, const string& s2);bool operator>(const string& s1, const string& s2);bool operator>=(const string& s1, const string& s2);bool operator==(const string& s1, const string& s2);bool operator!=(const string& s1, const string& s2);ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);
}

2.String.cpp

代码如下(示例):

#include"string.h"namespace bit
{const size_t string::npos = -1;void string::reserve(size_t n){if (n > _capacity){//cout << "reserve:" << n << endl;char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void string::push_back(char ch){if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;++_size;_str[_size] = '\0';}string& string::operator+=(char ch){push_back(ch);return *this;}void string::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}strcpy(_str + _size, str);_size += len;}string& string::operator+=(const char* str){append(str);return *this;}void string::insert(size_t pos, char ch){assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}// 挪动数据size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;++_size;}void string::insert(size_t pos, const char* s){assert(pos <= _size);size_t len = strlen(s);if (_size + len > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}size_t end = _size + len;while (end > pos + len - 1){_str[end] = _str[end - len];--end;}for (size_t i = 0; i < len; i++){_str[pos + i] = s[i];}_size += len;}void string::erase(size_t pos, size_t len){assert(pos < _size);if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{for (size_t i = pos + len; i <= _size; i++){_str[i - len] = _str[i];}_size -= len;}}size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}size_t string::find(const char* str, size_t pos){assert(pos < _size);const char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;}}string string::substr(size_t pos, size_t len){assert(pos < _size);// len大于剩余字符长度,更新一下lenif (len > _size - pos){len = _size - pos;}string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}return sub;}bool operator<(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) < 0;}bool operator<=(const string& s1, const string& s2){return s1 < s2 || s1 == s2;}bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}bool operator==(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) == 0;}bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}// 17:16继续istream& operator>>(istream& in, string& s){s.clear();const int N = 256;char buff[N];int i = 0;char ch;//in >> ch;ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}//in >> ch;ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916478.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916478.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

造成服务器内存不足的原因有什么

服务器在日常的运行过程中&#xff0c;会存储大量关于企业重要的数据信息&#xff0c;偶尔会出现内存飙升空间不足的情况&#xff0c;服务器内存作为服务器数据处理和存储的主要空间&#xff0c;异常占用会导致服务器性能降低&#xff0c;影响到企业业务的响应速度&#xff0c;…

JVM、Dalvik、ART垃圾回收机制

一、JVM垃圾回收机制&#xff08;桌面/服务器端&#xff09;1. 核心算法&#xff1a;分代收集新生代回收&#xff08;Minor GC&#xff09;触发条件&#xff1a;Eden区满时触发算法&#xff1a;复制算法&#xff08;Eden → Survivor区&#xff09;过程&#xff1a;存活对象在S…

数学专业转型数据分析竞争力发展报告

一、核心优势拆解&#xff08;1&#xff09;数学能力与数据分析对应关系数学课程数据分析应用场景比较优势说明概率论假设检验设计能准确判断统计显著性阈值实变函数数据质量评估异常值检测的严格性更高线性代数特征工程构建矩阵运算优化模型训练效率&#xff08;2&#xff09;…

JAVA进阶--MySQL

一.MySQL架构连接层:处理客户端连接服务,认证授权相关的操作服务层:最核心的一层&#xff08;核心服务功能&#xff09;,处理sql,包括sql优化,函数调用....存储引擎层:存储引擎是真正负责来操作数据的&#xff08;mysql中数据的存储和提取&#xff09;, mysql中有不同存储引擎,…

【架构】Docker简单认知构建

作为一个之前从来没有接触过Docker的倒霉蛋&#xff0c;想了解学习一下Docker 搜了CSDN和RUNOOB&#xff0c;得到的描述如下&#xff1a; Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包…

C++ std::list概念与使用案例

C std::list 概念详解 std::list 是 C 标准模板库&#xff08;STL&#xff09;中的一个双向链表容器。与 vector 和 array 不同&#xff0c;它不保证元素在内存中连续存储&#xff0c;而是通过指针将各个元素连接起来。 核心特性 双向链表结构&#xff1a; 每个元素包含指向前驱…

从0到1学Pandas(六):Pandas 与数据库交互

目录一、数据库基础操作1.1 连接数据库1.2 执行 SQL 查询1.3 创建与修改表结构二、数据导入导出2.1 从数据库读取数据2.2 将数据写入数据库2.3 大数据量处理三、数据库事务处理3.1 事务概念与实现3.2 批量数据更新3.3 错误处理与回滚四、数据库性能优化4.1 查询性能优化4.2 连接…

GitHub 趋势日报 (2025年07月26日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图602Qwen3-Coder573neko527hrms275BillionMail153Win11Debloat115hyperswitch57data…

机器人仿真(2)Ubuntu24.04下RTX5090配置IsaacSim与IsaacLab

目录 一、前言二、电脑配置三、配置步骤3.1 创建Conda环境3.2 安装PyTorch3.3 安装Isaac Sim3.4 安装Isaac Lab 四、总结 一、前言 博主自从去年开始就一直在关注Isaac Lab和Isaac Sim&#xff0c;但是一直以来由于手头设备只有4060&#xff0c;甚至没有达到最低配置16GB显存要…

DaVinci Resolve 19.0(达芬奇)软件安装包下载及详细安装教程|附带安装文件

[软件名称]&#xff1a;ArcGIS [软件大小]&#xff1a;2.99 GB [系统要求]&#xff1a;支持Win7及更高版本 [下载通道]: 迅雷网盘 [下载链接]:高速下载地址 https://pan.xunlei.com/s/VOW9nw-JV99A_7f_5hhpgqO2A1?pwdbufh# ⚠️:先用手机下载迅雷网盘保存到手机中&#xff0c…

Java学习第八十一部分——Shiro

目录 &#x1f4eb; 一、前言提要简介 &#x1f6e1;️ 二、核心功能介绍 ⚙️ 三、核心架构组件 ☕ 四、与Java的关系 ⚖️ 五、与Spring Security对比 &#x1f9e9; 六、典型应用场景 &#x1f48e; 七、总结归纳概述 &#x1f4eb; 一、前言提要简介 Apache Shiro 是…

虚拟机ubuntu20.04共享安装文件夹

ubuntu20.04共享安装文件夹 4.5 共享安装文件夹 将Windows存放安装文件的文件夹共享给虚拟机&#xff0c;如下图操作&#xff1a;如果是在ubuntu20.04中&#xff0c;还需要以下的操作&#xff1a; sudo mkdir /mnt/hgfs 此命令无效 sudo echo ‘vmhgfs-fuse /mnt/hgfs fu…

如何查看电脑后门IP和流量?

你是否也有以下经历&#xff1f;深夜&#xff0c;你的电脑风扇突然狂转&#xff0c;屏幕却一片寂静&#xff1b;每月流量莫名超标&#xff0c;账单高得离谱&#xff1b;鼠标偶尔不听使唤…这些可能不是电脑“闹脾气”&#xff0c;如何一探究竟&#xff1f; 想象一下&#xff1a…

分类预测 | MATLAB基于四种先进的优化策略改进蜣螂优化算法(IDBO)的SVM多分类预测

分类预测 | MATLAB基于四种先进的优化策略改进蜣螂优化算法(IDBO)的SVM多分类预测 目录分类预测 | MATLAB基于四种先进的优化策略改进蜣螂优化算法(IDBO)的SVM多分类预测分类效果基本介绍多策略量子自适应螺旋搜索算法研究摘要1. 引言1.1 研究背景1.2 研究意义1.3 研究目标2. 文…

Android 修改系统时间源码阅读

链接&#xff1a;XRefAndroid - Support Android 16.0 & OpenHarmony 5.0 (AndroidXRef/AospXRef) 这里看的Android 10的代码&#xff0c;选中Android 10&#xff0c;勾选所有工程&#xff0c;搜索DateTimeSettings‌&#xff1a; 看到showTimePicker应该是显示一个设置时…

关于自定义域和 GitHub Pages(Windows)

GitHub Pages 支持使用自定义域,或将站点 URL 的根目录从默认值(例如 )更改为您拥有的任何域,比如octocat.github.io。 谁可以使用此功能? GitHub Pages 在公共存储库中提供 GitHub Free 和 GitHub Free for organizations,在公共和私有存储库中提供 GitHub Pro、GitHub …

自动驾驶领域中的Python机器学习

数据预处理与特征工程 在自动驾驶系统中&#xff0c;数据是驱动决策的核心。从传感器&#xff08;如摄像头、激光雷达、毫米波雷达&#xff09;收集的原始数据通常包含噪声、缺失值和异常值&#xff0c;需要进行系统的预处理。Python的pandas库提供了强大的数据处理能力&#x…

PROFINET转CAN通讯协议转换速通汽车制造

在汽车系统领域之外&#xff0c;控制器局域网&#xff08;CAN&#xff09;总线技术亦广泛应用于多种工业环境。其固有的稳健性、可靠性与灵活性&#xff0c;使其成为工业自动化及控制系统中设备间通信的理想选择。CAN 总线技术在工业应用中的关键领域包括机器控制、传感器网络以…

影刀RPA_小红书笔记批量采集_源码解读

一、项目简介本项目是一个基于影刀RPA的小红书笔记批量采集工具&#xff0c;能够通过两种模式获取小红书平台的软文数据&#xff1a;搜索内容抓取和自定义链接抓取。工具使用Chrome浏览器自动化技术&#xff0c;实现了从网页数据采集、解析到Excel导出的完整流程。支持获取笔记…

以使命为帆,结业是重新出发的号角

站在私教班结业典礼的讲台上&#xff0c;望着眼前一张张闪烁着力量的面孔&#xff0c;我心中始终萦绕着一个信念&#xff1a;所有的相遇&#xff0c;都是为了共同奔赴一件更有意义的事。今天不是终点&#xff0c;而是 “使命的启程”—— 我们因不甘而相聚&#xff1a;不甘心行…