实现C++自定义的String类

一、简介

  • 采用了COW写时复制的方式实现,即在每个String类数据域之前用了4个字节的空间进行引用计数。通过拷贝构造函数或者赋值运算符函数进行赋值时不会重新开辟空间,只会对引用计数加一,当有修改操作时,才会重新开辟新的空间;
  • 内部定义了一个char类型的内部代理类,用于解决String类重载下标运算符后无法区分读写操作的问题。

二、头文件

#pragma once
#include <iostream>class String {class CharProxy { // char类型的代理内部类public:CharProxy(int index, String &str);char &operator=(const char &c);friend std::ostream &operator<<(std::ostream &os, const CharProxy &charPorxy);private:int _index;	   // 下标String &_this; // 指向外部类对象};public:String();String(const char *pstr);String(const String &str);~String();String &operator=(const String &str);String &operator=(const char *pstr);String &operator+=(const String &str);String &operator+=(const char *pstr);String::CharProxy operator[](std::size_t index);std::size_t size()const; // 字符串的长度const char* c_str()const; // 返回一个C风格的字符串friend bool operator==(const String &leftStr, const String &rightStr);friend bool operator!=(const String &leftStr, const String &rightStr);friend bool operator<(const String &leftStr, const String &rightStr);friend bool operator>(const String &leftStr, const String &rightStr);friend bool operator<=(const String &leftStr, const String &rightStr);friend bool operator>=(const String &leftStr, const String &rightStr);friend std::ostream &operator<<(std::ostream &os, const String &str);friend std::istream &operator>>(std::istream &is, String &str);int refCount(); // 返回引用计数friend std::ostream &operator<<(std::ostream &os, const CharProxy &charPorxy);
private:char *malloc(const char *pstr = nullptr); // 为字符串申请空间void release(); // 释放字符串的空间void initRefCount(); // 初始化引用计数void increaseRefCount(); //增加引用计数void decreaseRefCount(); // 减少引用计数static const int refCountLength = 4; // 引用计数所占字节数char * _pstr;
};String operator+(const String &thisStr, const String &otherStr);
String operator+(const String &thisStr, const char *otherpStr);
String operator+(const char *thisPstr, const String &otherStr);

三、String实现

#include <cstring>
#include "08_MyString.hh"using namespace std;/*** 内部代理类有参构造函数 
*/
String::CharProxy::CharProxy(int index, String &str) :_index(index), _this(str) {cout << "CharProxy()" << endl;
}/*** 重载内部代理类的赋值运算符=
*/
char &String::CharProxy::operator=(const char &c) {	cout << "char &operator=(const char &c)" << endl;if (_index < strlen(_this._pstr)) { // 未越界if (*(int*)(_this._pstr - refCountLength) > 1) { // 判断引用计数是否大于1_this.decreaseRefCount(); // 原空间引用计数-1char *newStr = _this.malloc(_this._pstr); // 开辟新空间strcpy(newStr, _this._pstr);				_this._pstr = newStr;_this.initRefCount(); // 初始化引用计数(此处时机一定要在赋值了新串之后)		}_this._pstr[_index] = c; // 修改元素return _this._pstr[_index];}else {static char nullchar = '\0';return nullchar;}	
}/*** 重载内部代理类的输出运算符<<
*/
ostream &operator<<(std::ostream &os, const String::CharProxy &charPorxy) {if (charPorxy._index < strlen(charPorxy._this._pstr)) {os << charPorxy._this._pstr[charPorxy._index];}else {os << "out of range";}return os;
}/*** 为字符串申请空间 * 初始化并偏移到数据的位置
*/
char *String::malloc(const char *pstr) { if (pstr == nullptr) {return new char[1 + refCountLength]() + refCountLength; } else {return new char[strlen(pstr) + 1 + refCountLength]() + refCountLength;}
}/*** 释放字符串的空间
*/
void String::release() {decreaseRefCount();if (refCount() == 0) {delete [] (_pstr - refCountLength);_pstr = nullptr;cout << "release()......." << endl;}
}/*** 初始化引用计数
*/
void String::initRefCount() {*(int*)(_pstr - refCountLength) = 1;
}/*** 增加引用计数
*/
void String::increaseRefCount(){++*(int*)(_pstr - refCountLength);
}
/*** 减少引用计数
*/
void String::decreaseRefCount(){--*(int*)(_pstr - refCountLength);
}
/*** 返回引用计数
*/
int String::refCount() {return *(int*)(_pstr - refCountLength);
}/*** 无参构造函数
*/
String::String()
: _pstr(malloc())
{initRefCount();strcpy(_pstr, "");	cout << "String()" << endl;
}/*** 有参构造函数
*/
String::String(const char *pstr) 
: _pstr(malloc(pstr)) 
{initRefCount();strcpy(_pstr, pstr);cout << "String(const char *pstr) " << endl;
}/*** 拷贝构造函数
*/
String::String(const String &str)
: _pstr(str._pstr) // 浅拷贝
{increaseRefCount();cout << "String(const String &str)" << endl;
}/*** 析构函数
*/
String::~String() {release();
}/*** 重载赋值运算符函数
*/
String &String::operator=(const String &str) {if (this != &str && strcmp(_pstr, str._pstr) != 0) { // 跳过自赋值 和相同字符串release();_pstr = str._pstr; // 浅拷贝	increaseRefCount();} return *this; 
}
String &String::operator=(const char *pstr) {if (strcmp(_pstr, pstr) != 0) { // 跳过相同字符串release(); // 删除旧字符串_pstr = malloc(pstr); // 申请新空间 initRefCount(); // 初始化引用计数strcpy(_pstr, pstr); // 复制	}return *this;
}/*** 重载+=
*/
String &String::operator+= (const String &str) {if (str._pstr != nullptr && strlen(str._pstr) > 0) {size_t newLen = strlen(_pstr) + strlen(str._pstr) + refCountLength + 1;char *newStr = new char[newLen]() + refCountLength; // 偏移到数据的位置strcat(newStr, _pstr);strcat(newStr, str._pstr);release(); // 删除旧字符串_pstr = newStr;initRefCount(); // 初始化引用计数(此处时机一定要在赋值了新串之后)}return *this;
}
String &String::operator+= (const char *pstr) {if (pstr != nullptr && strlen(pstr) > 0) {size_t newLen = strlen(_pstr) + strlen(pstr) + refCountLength + 1;char *newStr = new char[newLen]() + refCountLength; // 偏移到数据的位置strcat(newStr, _pstr);strcat(newStr, pstr);release(); // 删除旧字符串_pstr = newStr;initRefCount(); // 初始化引用计数(此处时机一定要在赋值了新串之后)}return *this;
}/*** 重载下标运算符
*/
String::CharProxy String::operator[] (size_t index) {return String::CharProxy(index, *this);
}/*** 获取字符串长度
*/
size_t String::size() const {return strlen(_pstr);
}/*** 返回C风格字符串
*/
const char *String::c_str() const {return _pstr;
}/*** 重载==
*/
bool operator==(const String &leftStr, const String &rightStr) {return strcmp(leftStr._pstr, rightStr._pstr) == 0 ? true : false;
}
/*** 重载!=
*/
bool operator!=(const String &leftStr, const String &rightStr) {return strcmp(leftStr._pstr, rightStr._pstr) != 0 ? true : false;
}
/*** 重载<
*/
bool operator<(const String &leftStr, const String &rightStr) {return strcmp(leftStr._pstr, rightStr._pstr) < 0 ? true : false;
}
/*** 重载>
*/
bool operator>(const String &leftStr, const String &rightStr) {return strcmp(leftStr._pstr, rightStr._pstr) > 0 ? true : false;
}
/*** 重载<=
*/
bool operator<=(const String &leftStr, const String &rightStr) {int res = strcmp(leftStr._pstr, rightStr._pstr); return res > 0 ? false : true;
}
/*** 重载>=
*/
bool operator>=(const String &leftStr, const String &rightStr) {int res = strcmp(leftStr._pstr, rightStr._pstr); return res < 0 ? false : true;
}/*** 重载输出流函数
*/
ostream &operator<< (ostream &os, const String &str) {os << str._pstr;return os;
}/*** 重载输入流函数
*/
istream &operator>> (istream &is, String &str) {if (strlen(str._pstr) > 0) {str = ""; // str非空就先清空str}char buf[1024];while (1) {is.clear(); // 恢复流的状态bzero(buf, sizeof(buf)); // 清空bufis.get(buf, sizeof(buf)); // 读取一个buf的大小int len = strlen(buf);if (len == 0) { // buf长度为0时退出循环 break;}	str += buf;}return is;
}/*** 重载+
*/
String operator+(const String &thisStr, const String &otherStr) {if (strlen(thisStr.c_str()) == 0) {return otherStr;}if (strlen(otherStr.c_str()) == 0) {return thisStr;}String temp(thisStr);temp+=otherStr;return temp;
}
String operator+(const String &thisStr, const char *otherPstr) {if (strlen(thisStr.c_str()) == 0) {return String(otherPstr);}if (strlen(otherPstr) == 0) {return thisStr;}String temp(thisStr);temp+=otherPstr;return temp;
}
String operator+(const char *thisPstr, const String &otherStr) {if (strlen(thisPstr) == 0) {return otherStr;}if (strlen(otherStr.c_str()) == 0) {return String(thisPstr);}String temp(thisPstr);temp+=otherStr;return temp;
}

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

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

相关文章

es文档操作命令

文档操作 documents 创建数据&#xff08;put&#xff09; 向 user 索引下创建3条数据 PUT /user/_doc/1 {"name":"zhangsan","age":18,"sex":"男","info":"一顿操作猛如虎&#xff0c;一看工资2500"…

码云简化版使用教程

码云简化版使用教程 ①创建本地项目 ②在本地项目根目录下创建git相关目录及文件 ③在码云上创建新的仓库 ④在本地项目中配置仓库地址&#xff0c;提交项目内容 下面直接从第二步开始讲解 在本地项目根目录下创建git相关目录及文件 1、打开项目根目录&#xff0c;进入cmd界…

Linux应用 线程同步之互斥锁

1、概念 1.1 定义 互斥锁&#xff08;Mutex&#xff09;&#xff0c;又称互斥型信号量&#xff0c;是一种特殊的二值性信号量&#xff0c;主要用于实现对共享资源的独占式处理。任意时刻&#xff0c;互斥锁的状态只有两种&#xff1a;开锁或闭锁。当有任务持有时&#xff0c;…

旧衣服回收小程序开发,“互联网+”模式下巨大收益

近年来&#xff0c;在人们生活水平的提高下&#xff0c;旧衣物随之增加&#xff0c;如何处理旧衣服成为了当下大众所困扰的问题。 当下&#xff0c;旧衣回收行业已经成为了一个新的热门行业&#xff0c;我国人口众多&#xff0c;旧衣物的市场规模也在不断扩大&#xff0c;市场…

【QT入门】qmake和cmake的简单区别

声明&#xff1a;该专栏为本人学习Qt知识点时候的笔记汇总&#xff0c;希望能给初学的朋友们一点帮助(加油&#xff01;) 往期回顾&#xff1a; 【QT入门】Windows平台下 QT的编译过程-CSDN博客 【QT入门】VS2019QT的开发环境配置-CSDN博客 【QT入门】VS2019和QT Creator如何添…

基于springboot+vue的房屋交易平台

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

代码随想录算法训练营Day48 | LeetCode121. 买卖股票的最佳时机、LeetCode122.买卖股票的最佳时机II

LeetCode121. 买卖股票的最佳时机 动规五部曲&#xff1a; 1、dp[i][0]:在第i天持有股票的最大收入&#xff1b;dp[i][1]:在第i天不持有股票的最大收入。 2、递推公式&#xff1a;第i天持有股票&#xff0c;有两种情况&#xff1a;前一天已经持有&#xff0c;当天刚买入&#…

Greetings

Problem - 1915F - Codeforces 题意 给一些(l,r)找到所有能够包含(l,r)的数目 引入 也就是找逆序对个数 要用到归并排序中的思想&#xff1a; //https://www.luogu.com.cn/problem/P1216 #include<iostream> #include<cstdio> #include<stack> #include…

用python如何实现智能合约?如何使用remix编写solidity智能合约并部署上链

目录 用python如何实现智能合约? 直接展示下成功界面 下面分步骤说: remix代码 python链接remix代码

将查询出来数据中相对应的字段根据枚举类更改为其中文内容

&#x1f413;1.通过mapper.xml文件中的内容使用casewhen进行更换字段内容 SELECT case user_type when 101000 then 李明 when 101001 then 王丽 when 101002 then 王小黑 when 101003 then 王大黑 when 101004 then 超级大王 when 101005 then 小董 else end as 别称 from…

python面向对像之第二次笔记

python面向对像 一、面向对象的三大特性面向对象包含3大主要特性&#xff1a;封装私有成员继承复写 pass关键字多态 总结 一、面向对象的三大特性 面向对象包含3大主要特性&#xff1a; 封装 封装是面向对象编程中的一个重要概念&#xff0c;它指的是将数据&#xff08;属性&a…

STM32信息安全 1.2 课程架构介绍:芯片生命周期管理与安全调试

STM32信息安全 1.2 课程架构介绍&#xff1a;STM32H5 芯片生命周期管理与安全调试 下面开始学习课程的第二节&#xff0c;简单介绍下STM32H5芯片的生命周期和安全调试&#xff0c;具体课程大家可以观看STM32官方录制的课程&#xff0c;链接&#xff1a;1.2. 课程架构介绍&…

记一些有关Element Plus的样式修改

先记一个放着&#xff0c;后续慢慢补充。。。 一个 Vue 3 UI 框架 | Element Plus Radio 单选框 1、去除radio的圆圈 .box-radio {/deep/ .el-radio__input {display: none;} }

Leetcode 3085. Minimum Deletions to Make String K-Special

Leetcode 3085. Minimum Deletions to Make String K-Special 1. 解题思路2. 代码实现 题目链接&#xff1a;3085. Minimum Deletions to Make String K-Special 1. 解题思路 这一题思路上来说的话我们只需要统计一下word当中所有的字符出现的频次&#xff0c;然后依次排序&…

【QT入门】VS2019和QT Creator如何添加第三方模块

声明&#xff1a;该专栏为本人学习Qt知识点时候的笔记汇总&#xff0c;希望能给初学的朋友们一点帮助(加油&#xff01;) 往期回顾&#xff1a; 【QT入门】什么是qt&#xff0c;发展历史&#xff0c;特征&#xff0c;应用&#xff0c;QtCreator-CSDN博客 【QT入门】Windows平台…

模方信创版正式上线!支持水面一键修复、道路置平、纹理编辑...

现在国家大力推进信创国产化软硬件替代的政策背景下&#xff0c;大势智慧重磅发布模方信创版&#xff0c;以满足用户对在信创环境下进行实景三维模型修饰与编辑的需求。 模方信创版与重建大师信创版、DasViewer信创版一道&#xff0c;构筑起三维重建信创生态的“铁三角”&…

Unity PS5开发 天坑篇 之 DEVKit环境部署与系统升级02

上一篇各位大神们已经收到了SONY官方免费寄送的PS5开发机与测试机&#xff0c;恭喜大家成为SONY的开发者, 本篇继续PS5开发机的部署与开发套件使用。 一, PC安装PS5 SDK与系统升级 1. PC/PS5 SDK Manager下载安装包 登录开发者账号后&#xff0c;Development->Resources&a…

微信小程序处理ArrayBuffer拼接问题

微信小程序中与设备进行通讯时&#xff0c;经常需要在前面加一些字节&#xff0c;或者处理分包的时候需要加一些字节过去&#xff0c;如果在后端很好操作&#xff0c;但是在小程序中由于ArrayBuffer不支持直接操作&#xff0c;非常不方便 最近一个与设备通讯中&#xff0c;需要…

在字符串中替换指定的子字符串

得到的路径是 url : "/devapihttps://ossdcd.nyncjxx.com/202403/18/1710744688215/xiaomai.jpg" 去除/dev-api&#xff0c;只要后面的 url.replace(/dev-api, "")string.replace(searchValue, newValue)let originalString "Hello, World!"; l…

描述一下使用过的后端框架及其特点

一、描述一下使用过的后端框架及其特点 Django Django是一个用Python编写的高级Web框架&#xff0c;它遵循MVC设计模式&#xff0c;但更倾向于将其组件称为模型&#xff08;Model&#xff09;、模板&#xff08;Template&#xff09;和视图&#xff08;View&#xff09;&am…