C++——string的模拟实现(上)

目录

引言

成员变量

1.基本框架

成员函数

1.构造函数和析构函数

2.拷贝构造函数

3.容量操作函数

3.1 有效长度和容量大小

3.2 容量操作

3.3 访问操作

(1)operator[]函数

(2)iterator迭代器

3.4 修改操作

(1)push_back()和append()

(2)operator+=函数


引言

在 C++——string的了解和使用 中,我们学习了string的一些基础用法。接下来我们可以试着模拟实现string。

在C++中,std::string是一个功能强大且广泛使用的类,用于处理字符串。然而,了解其内部实现原理对于深入理解C++和编写高效代码至关重要。通过模拟实现一个简单的string类,我们可以更好地理解字符串的存储、管理以及操作。这不仅有助于我们更好地使用std::string,还能让我们在遇到特定需求时,能够自定义字符串类来满足这些需求。

成员变量

1.基本框架

为了与STL库中的string区分开来,我们要使用命名空间namespace进行封装。

char* _str:指向字符数组的指针,用于存储字符串的实际内容。

size_t  _size:表示字符串中有效字符的数量。

size_t  _capacity:表示字符数组的容量,即可以存储的最大字符数量(包括结尾的空字符\0)。

namespace My_string
{class string {public:// ...private:char* _str;size_t _size;size_t _capacity;};
}

成员函数

老规矩,我们在 string.h 中,声明函数;在 string.cpp 中,实现函数的功能。

1.构造函数和析构函数

构造函数:接受一个C风格字符串作为参数,计算其长度,分配足够的内存来存储该字符串及其结尾的空字符,并复制字符串内容。

析构函数:释放分配给字符串的内存,并将指针设置为nullptr,以避免悬挂指针问题。同时,将_size和_capacity设置为0,表示对象已销毁。

string.h:

namespace My_string
{class string {public:string(const char* str);//构造函数~string();				//析构函数private:char* _str;size_t _size;size_t _capacity;};
}

string.cpp:

#include"string.h"
namespace My_string
{// 构造函数string::string(const char* str){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];    // +1用于储存'\0'strcpy(_str, str);}// 析构函数string::~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}
}

我们可以测试一下:

通过调试观察一下:

调用构造函数:

调用析构函数:

2.拷贝构造函数

拷贝构造函数:接受一个string对象作为参数,分配足够的内存来存储原对象的字符串内容,并复制该内容。

这里提供了三种实现方式,包括直接复制、使用临时对象进行深拷贝以及使用swap函数进行资源转移。

string.h:

string(const string& str);		//拷贝构造函数

string.cpp:

// 拷贝构造函数(1)
string::string(const string& str)
{_str = new char[str._capacity + 1];	//额外多给一个空间,用于存放'/0'strcpy(_str, str._str);		//拷贝数据_capacity = str._capacity;	//设置容量_size = str._size;			//设置有效数据个数
}

我们在这里也有其他的方法可以实现拷贝构造:

// 拷贝构造函数(2)
string::string(const string& str)
{string tmp(str._str);std::swap(tmp._str, _str);std::swap(tmp._size, _size);std::swap(tmp._capacity, _capacity);
}

以上代码还可以接着简化:

string::string(const string& str)
{string tmp(str._str);swap(tmp);			// 这里的swap我们接下来会定义
}

3.容量操作函数

3.1 有效长度和容量大小

我们先写这两个函数:

size()和capacity():分别返回字符串的有效长度和字符数组的容量。

string.h:

		size_t size() const;			// size()函数size_t capacity() const;		// capacity()函数

string.cpp:

// size()函数
size_t string::size() const
{return _size;
}// capacity()函数
size_t string::capacity() const
{return _capacity;
}
3.2 容量操作

c_str():返回一个指向以空字符结尾的字符数组的指针,该数组包含与string对象相同的字符序列。这允许将string对象与接受C风格字符串的函数一起使用。

empty():检查字符串是否为空(即长度为0)。

erase():删除字符串中指定位置的字符或子字符串。

string.h:

const char* c_str() const;		// c_str()函数
bool empty() const;				// empty()函数
void erase(size_t pos = 0, size_t len = npos);    // erase()函数

string.cpp:

// c_str()函数
const char* string::c_str() const
{return _str;
}
// empty()函数
bool string::empty() const
{return _size == 0;
}
// erase()函数
void string::erase(size_t pos,size_t len)
{assert(pos < _size);				 if (len == npos || len >= _size - pos){_str[pos] = '\0';		// 位置pos置为'\0'_size = pos;			// 有效元素个数为pos个}else	// len小于后面的字符个数{// 将后面的字符拷贝到pos位置strcpy(_str + pos, _str + pos + len);_size -= len;			// 更新有效元素}
}

接下来再来实现扩容函数reserve()和resize():

reserve():增加字符数组的容量,以确保可以存储至少n个字符。如果当前容量不足,则分配新的内存并复制现有内容。

resize():改变字符串的大小。如果新大小大于当前大小,则添加新字符(默认为\0);如果新大小小于当前大小,则删除多余的字符。

string.h:

// 预留空间
void reserve(size_t n);
// resize()函数
void resize(size_t n, char ch = '\0');

string.cpp:

// 预留空间
void string::reserve(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}
}
// resize()函数
void string::resize(size_t n, char ch)
{if (n > _size){if (n > _capacity){reserve(n);}// 使用 memset 函数将字符 ch // 填充到新添加的空间中memset(_str + _size, ch, n - _size);}_size = n;_str[n] = '\0';
}
3.3 访问操作
(1)operator[]函数

operator[]函数的功能:返回pos位置的字符

string.h:

// 非const版本
char& operator[](size_t pos);	//operator[]函数
// const版本
const char& operator[](size_t pos)const;

string.cpp:

// operator[]函数
char& string::operator[](size_t pos)
{assert(pos < _size);return _str[pos];
}
// const版本
const char& string::operator[](size_t pos)const
{assert(pos < _size);return _str[pos];
}

来个简单的代码测试一下:

(2)iterator迭代器

迭代器:提供begin()和end()函数来返回指向字符串开头和结尾的迭代器。这里简化了迭代器的实现,将其视为指向字符数组的指针。然而,在实际应用中,迭代器通常是一个更复杂的类,提供了更多的功能和安全性检查。

string.h:

//const版本的iterator
const_iterator begin() const;	//提供const_iterator begin()函数
const_iterator end() const;		//提供const_iterator end()函数//非const版本的iterator
iterator begin();				//提供iterator begin()函数
iterator end();					//提供iterator end()函数

string.cpp:

string::iterator string::begin()
{return _str;
}
string::iterator string::end()
{return _str + _size;
}
string::const_iterator string::begin() const
{return _str;
}
string::const_iterator string::end() const
{return _str + _size;
}

还是老样子,我们使用一个简单的函数测试一下:

void test3()
{My_string::string str("hello");for (auto i : str){cout << i << " ";}cout << endl;My_string::string::iterator it1 = str.begin();while (it1 != str.end()){cout << *it1 << " ";++it1;}cout << endl;My_string::string::iterator it2 = str.end();if (it2 != str.begin()) { // 检查避免直接解引用 end()  --it2; // 先移动到一个有效的位置  while (it2 != str.begin()){std::cout << *it2 << " ";--it2;}std::cout << *it2 << " "; // 输出最后一个字符(begin() 之前的字符)  }std::cout << std::endl;
}

输出结果为:

3.4 修改操作
(1)push_back()和append()

string.h:

// 尾插一个字符
void push_back(char ch);
// 尾插一个字符串
void append(const char* str);

string.cpp:

//尾插一个字符
void string::push_back(char ch)
{if (_capacity == _size){size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}_str[_size] = ch;_str[_size + 1] = '\0';_size++;
}//尾插一个字符串
void string::append(const char* str)
{size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}strcpy(_str+_size, str);_size += len;			
}
(2)operator+=函数

我们可以借助上面两个函数实现operator+=函数。

string.h:

//operator+=函数可以构成重载,函数名相同,参数不同
string& operator+=(char ch);			// 字符相加
string& operator +=(const char* str);	// 字符串相加

string.cpp:

string& string::operator+=(char ch)
{// 调用push_back()函数push_back(ch);		return *this;
}
string& string::operator+=(const char* str)
{append(str);return *this;
}

来测试一下:

operator+=函数返回的是对象本身。

内置类型的+=运算符返回值的副本。

自定义类型的+=运算符通常返回对象的引用(即*this),以支持链式操作和避免复制。

———————————————————————————————————————————

以上为string模拟实现的第一篇

求点赞收藏评论关注!!!

感谢各位大佬!!!

第二篇链接:C++——string的模拟实现(下)

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

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

相关文章

【C++单调栈 贡献法】907. 子数组的最小值之和|1975

本文涉及的基础知识点 C单调栈 LeetCode907. 子数组的最小值之和 给定一个整数数组 arr&#xff0c;找到 min(b) 的总和&#xff0c;其中 b 的范围为 arr 的每个&#xff08;连续&#xff09;子数组。 由于答案可能很大&#xff0c;因此 返回答案模 109 7 。 示例 1&#x…

多eSIM配置文件(MEP)

根据在fediverse上的一个回复&#xff0c;Google Pixel 7和8都应该支持MEP&#xff08;多eSIM配置文件&#xff09;。这一信息在Reddit上的一个帖子中似乎得到了确认&#xff0c;该帖子讨论了eSIM MEP和双eSIM功能。 如果您想进一步研究并检查是否可以通过DIAG&#xff08;诊断…

RabbitMQ是一个开源的消息代理和队列服务器

RabbitMQ是一个开源的消息代理和队列服务器&#xff0c;它基于AMQP&#xff08;Advanced Message Queuing Protocol&#xff0c;高级消息队列协议&#xff09;协议实现&#xff0c;同时也支持其他消息协议如STOMP、MQTT等。作为一个可靠的消息传递服务&#xff0c;RabbitMQ在分…

NtripShare Cloud平台之CORS服务之基准站RTCM坐标编辑

最近有点累&#xff0c;一直在摸鱼&#xff0c;想在平差方面做点事情&#xff0c;但是一直在构思应该怎么去做&#xff0c;有想法的朋友可以交流。 收到了TW和国内顶尖测绘行业朋友的需求&#xff1a; 1、将NtripShare Cloud的CORS服务模块由单基站模块改为VRS。 2、由于电离…

了解光耦合器输入输出关系---腾恩科技

光耦合器&#xff0c;也称为光隔离器&#xff0c;是电子电路中必不可少的元件&#xff0c;主要用于在隔离部分之间传输信号&#xff0c;同时防止电噪声或高压影响敏感元件。其独特的设计使它们能够在没有直接电接触的情况下&#xff0c;弥合不同电压域之间的差距。在本文中&…

Java基础第四天(实训学习整理资料(四)Java中的方法(函数))

一、定义 方法也叫代码块&#xff0c;用于实现功能代码的封装&#xff0c;方便调用。主要目的是实现代码复用。 二、方法和函数的关系 方法&#xff1a;&#xff08;面向对象&#xff09;在类中定义的成员。&#xff08;成员方法&#xff09;属于类创建出的对象的功能。 函…

Spring Boot驱动的Web版酒店客房管理系统

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理酒店客房管理系统的相关信息成为必然。开发…

小柴冲刺软考中级嵌入式系统设计师系列二、嵌入式系统硬件基础知识(5)定时器和计数器

越努力&#xff0c;越幸运&#xff01; 兄弟们&#xff0c;要搬家到上海滴水湖了 职业生涯又迎来一次比较重要的变动 郑州->上海->上海临港 哈哈哈 flechazo 小柴冲刺软考中级嵌入式系统设计师系列总目录 一、硬件定时器 从硬件角度来看&#xff0c;定时器&#xf…

学习--图像信噪比

目录 图像信噪比 图像信噪比 图像信噪比的计算公式&#xff1a; 其中&#xff0c; M M M和 N N N分别表示图像长度和宽度上的像素数。 f ( i , j ) f(i,j) f(i,j) 和 g ( i , j ) g(i,j) g(i,j)分别是原始图像和去噪后的图像在点 ( i , j ) (i,j) (i,j)处的像素值。 信噪…

Redis_写时复制(cow)

Redis会根据配置&#xff0c;每隔一段时间中对Redis服务中当下的数据集进行快照。配置自动生成rdb文件&#xff0c;后台使用的是bgsave方式。 save 60 1000 //关闭RDB只需要将所有的save保存策略注释掉即可Redis借助操作系统提供的写时复制技术&#xff08;Copy-On-Write, COW…

SYN590RL 300MHz至450MHz ASK接收机芯片IC

一般描述 SYN590RL是赛诺克全新开发设计的一款宽电压范围,低功耗,高性能,无需外置AGC电容&#xff0c;灵敏度达到典型-110dBm&#xff0c;300MHz”450MHz 频率范围应用的单芯片ASK或OOK射频接收器。 SYN59ORL是一款典型的即插即用型单片高集成度无线接收器&…

vue elementui el-table实现增加行,行内编辑修改

需求&#xff1a; 前端进行新增表单时&#xff0c;同时增加表单的明细数据。明细数据部分&#xff0c;可进行行编辑。 效果图&#xff1a; <el-card><div slot"header"><span style"font-weight: bold">外来人员名单2</span><…

代码随想录算法训练营第46期Day43

leetcode.322零钱兑换 class Solution { public: //无限个硬币->完全背包int coinChange(vector<int>& coins, int amount) {vector<int> dp(10010,INT_MAX);//dp代表的在某个数值下最小的硬币数&#xff0c;要求是最小的硬币数&#xff0c;所以初始值要尽可…

FreeSWITCH JSON API

仅举几例&#xff1a; fs_cli -x json {"command" : "status", "data" : ""} fs_cli -x json {"command" : "sofia.status", "data" : ""} fs_cli -x json {"command" : "…

面试域——技术面试准备

摘要 来到技术面试这环节有两种情况&#xff0c;其一&#xff1a;这场技术面试可能就是一个面试官KPI面试&#xff08;就是面试工作量&#xff0c;这个面试你是不可能过。&#xff09;如今的就业环境下&#xff0c;人力资源部门也是有考核指标。如果遇到这样的面试你就放平心态…

NLP实践项目1——判断推文的负面情绪

数据来源&#xff1a;https://datahack.analyticsvidhya.com/contest/linguipedia-codefest-natural-language-processing-1/?utm_sourceword-embeddings-count-word2veec&utm_mediumbloghttps://datahack.analyticsvidhya.com/contest/linguipedia-codefest-natural-lang…

FPGA开发时,什么情况下使用BRAM,什么情况下使用DRAM

DRAM&#xff1a;Distributed RAM&#xff0c;DRAM是用逻辑单元拼出来的。 BRAM&#xff1a;Block RAM&#xff0c;BRAM是fpga中定制的ram资源。 较大的存储应用&#xff0c;建议用block ram ; 零星的小ram&#xff0c;一般就用distributed ram。但这只是个一般原则&#xff0…

Linux中exec命令和xargs命令的使用

文章目录 exec基本用法选项实用示例 xargs基本用法选项实用示例 exec 在Linux系统中&#xff0c;xargs是一个非常有用的命令行工具&#xff0c;它能够将标准输入数据转化为命令行参数。xargs可以读取来自标准输入的数据&#xff0c;并将其作为参数传递给其他命令。以下是一些x…

别名联想路径,前端项目输入@/自动出提示目录和文件

如果在引入文件时&#xff0c;想要输入/后自动提示目录该如何做呢&#xff1f; 1.在项目的根目录下新增jsconfig.json文件 注意&#xff1a;一定得是根目录下&#xff0c;这个文件是个固定的名字&#xff0c;vscode在启动的时候会自动读取这个配置文件。 2.添加json格式的配置项…

反射、动态代理、SPI机制在RPC框架中应用

Java反射的理解 Java 反射机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类中的所有属性和方法&#xff0c;对于任意一个对象&#xff0c;都能够调用它的任意一个方法和属性&#xff1b;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语…