【C++初阶】9. string类的模拟实现

这篇具有很好参考价值的文章主要介绍了【C++初阶】9. string类的模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

string类的完整实现放这里啦!快来看看吧

1. string类的成员

string类的作用就是将字符串类型实现更多功能,运算符重载,增删改查等等操作,所以其成员就包含char*的字符串

private:
		char* _str;
		size_t _capacity;
		size_t _size;

2. 构造函数

2.1 带参构造函数

在之前的学习过程中,我们了解到类中存在的六个默认函数,其中就包含默认构造函数,那么对于string类是否需要用户自己实现构造函数呢?
答案是需要的,我们需要根据字符串的长度开辟空间,也需要将字符串拷贝到开辟的空间当中

		// 带参的构造函数
		string(const char* str)
		{
			_capacity = strlen(str);
			_size = _capacity;
			_str = new char[_capacity + 1];

			strcpy(_str, str);
		}

我们的代码实现中_capacity是计算到’\0’停止,所以在堆上new的时候要加1,给’\0’预留空间

2.2 不带参构造函数

		string()
		{
			_str = new char[1];
			_str[0] = '\0';
			_capacity = _size = 0;
		}

不带参数就开辟1个字节的空间存放\0

2.3 默认缺省构造函数

		string(const char* str = "")
		{
			_capacity = strlen(str);
			_size = _capacity;
			_str = new char[_capacity + 1];

			strcpy(_str, str);
		}

对于不传参的string类初始化,则是采用默认值的方式"" 该字符串自带斜杠0

这里需要区分清楚:‘\0’ / “\0” / “” 这几种情况的区别:

  • '\0’是字符\0 ASCII码值为0 相当于nullptr 拿nullptr作为默认值,后面strlen直接报错
  • 而"\0" 则是用两个\0初始化字符串
  • ""就是单纯的\0

3. 拷贝构造函数

那么拷贝构造是否也需要用户实现呢?
答案是需要的,因为string类的构造会开辟新空间,那么要实现对空间的深拷贝就需要自己实现

		// 深拷贝
		string(const string& s)
		{
			_capacity = s._size;
			_size = _capacity;
			_str = new char[_capacity + 1];

			strcpy(_str, s._str);
		}

4. 赋值重载函数

// s1 = s3;
string& operator=(const string& s)
{
	if (this != &s)
	{
		char* tmp = new char[s._capacity + 1];
		strcpy(tmp, s._str);

		delete[] _str;
		_str = tmp;

		_size = s._size;
		_capacity = s._capacity;
	}
	return *this;
}

首先要判断f赋值符号左右两边是否是同一对象,是则直接返回*this,否则再进一步操作

拓展:现代写法的拷贝构造和赋值重载

【C++初阶】9. string类的模拟实现
【C++初阶】9. string类的模拟实现
【C++初阶】9. string类的模拟实现

5. 析构函数

~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}

6. c_str()

const char* c_str() const
		{
			return _str;
		}		

c_str 返回的是string类中的字符串数组的地址,对于流插入(<<) 会自动识别类型,const char* 类型会以字符串的形式打印输出%s
所以,string类通常用该接口打印字符串

7. size()

		size_t size() const
		{
			return _size;
		}

返回当前字符串长度(不包含\0) 最好设计成size_t 类型:因为size不会出现负数的情况

8. capacity()

size_t capacity() const
{
	return _capacity;
}

返回当前字符串容量

9. operator[]

		// 普通对象:可读可写
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

		// const对象:只读
		const char& operator[](size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}

对[]的重载,[]访问分为两种情况:普通对象(可修改数据)const对象(不可修改)
传引用返回更加高效,也可修改数据
记得assert断言,防止出现越界访问的情况

10. 迭代器的实现

迭代器的底层可能是指针,也可能不是(list等其他结构),在string类中迭代器的底层就是char* 类型的指针

		typedef char* iterator;

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

范围for循环的本质就是迭代器 范围for自动替换成迭代器中的begin和end,如果把begin替换成Begin也无法配对(报错)
【C++初阶】9. string类的模拟实现

11. reserve() – 调整字符串容量(扩容)

当我们要进行增删改查等操作时,如果空间过小则无法继续进行,需要扩容

		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;

				_capacity = n;
			}
		}

实现接口的方式就是在堆上重新找一块n大小的空间,将原空间拷贝过来并释放原空间
将_str指向新空间,将_capacity置为n

12. 尾插单个字符

		void push_back(char ch)
		{
			if (_size == _capacity)
			{
				size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newCapacity);
			}

			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}
		
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

在尾插单个字符的时候要注意,之前_size位置的元素是\0,所以在_size++之后要在将_size放入\0

13. 尾插字符串

		void append(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			strcpy(_str + _size, str);
			_size += len;
		}
			
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}

而尾插字符串时因为str自带\0,strcpy会拷贝\0,所以_size+_len 位置就是\0,不需要单独处理

14. 在任意位置插入单个字符

【C++初阶】9. string类的模拟实现

		string& insert(size_t pos,char ch)
		{
			assert(pos <= _size);
			if (_capacity == _size)
			{
				size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newCapacity);
			}

			size_t end = _size + 1;
			while (end > pos)
			{
				_str[end] = _str[end - 1];
				--end;
			}

			_str[pos] = ch;
			++_size;

			return *this;
		}

15. 在任意位置插入字符串

【C++初阶】9. string类的模拟实现

16. 删除len个字符

【C++初阶】9. string类的模拟实现

17. 查找字符/子串

【C++初阶】9. string类的模拟实现

18. 调整大小

【C++初阶】9. string类的模拟实现

19. 流插入、流提取

在之前的学习过程中,我们了解到流提取和流插入一般都不会实现成成员函数,因为istream / ostream 会抢占this指针的位置
提问:是不是流提取和流插入一定要实现成友元全局函数呢?
答:不是,全局函数是正确的(不能定义在类体内) 但是不一定要实现成友元,友元的作用是帮助我们去访问类内的成员。
【C++初阶】9. string类的模拟实现
流提取和流插入是为自定义类型而生的(C++),printf和scanf对内置类型非常友好但是无法识别自定义类型(C语言)
【C++初阶】9. string类的模拟实现
所以在打印string类时还是推荐使用流插入
【C++初阶】9. string类的模拟实现
经过get函数的优化已经可以基本实现流提取功能,但是针对众多字符的插入采用+=操作会导致频繁扩容的情况,那么如何优化呢?

优化1:临时空间减少扩容

【C++初阶】9. string类的模拟实现

优化2:覆盖数据

【C++初阶】9. string类的模拟实现
到这里string类就完整实现啦!撒花✿✿ヽ(°▽°)ノ✿文章来源地址https://www.toymoban.com/news/detail-489776.html

到了这里,关于【C++初阶】9. string类的模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】string类的模拟实现

    前言:在上一篇中我们讲到了string类的使用方法,今天我们将进一步的去学习string类,去底层看看它顺带模拟实现部分的内容。 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏分类:高质量C++学习 👈 💯代码仓库:卫卫周大胖的学习日记💫 💪关注博主和博主一起学习!一起努

    2024年03月21日
    浏览(43)
  • 【C++】String类的模拟实现。

    🎉博客主页:小智_x0___0x_ 🎉欢迎关注:👍点赞🙌收藏✍️留言 🎉系列专栏:C++初阶 🎉代码仓库:小智的代码仓库 string类中需要三个成员变量分别记录元素个数、容量和内容。还需要一个 size_t 类型npos-1表示整型的最大值。 这段代码是 string 类的构造函数。构造函数是在

    2024年02月13日
    浏览(43)
  • C++ 之 string类的模拟实现

    这学习我有三不学 昨天不学,因为昨天是个过去 明天不学,因为明天还是个未知数 今天不学,因为我们要活在当下,我就是玩嘿嘿~ –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–

    2024年04月27日
    浏览(32)
  • 【C++】——string类的介绍及模拟实现

    C语言中,字符串是以’\\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。所以我们今天来学习C++标准库中的string类。

    2024年02月07日
    浏览(56)
  • 【c++】string类的使用及模拟实现

    我们先了解一下什么是OOP思想 OOP思想,即面向对象编程(Object-Oriented Programming)的核心思想,主要包括“抽象”、“封装”、“继承”和“多态”四个方面。 抽象:抽象是忽略一个主题中与当前目标无关的那些方面,以便充分地注意与当前目标有关的方面。抽象并不打算了

    2024年04月11日
    浏览(36)
  • STL中的string类的模拟实现【C++】

    构造函数设置为缺省参数,若不传入参数,则默认构造为空字符串。字符串的初始大小和容量均设置为传入C字符串的长度(不包括’\\0’) 在模拟实现拷贝构造函数前,我们应该首先了解深浅拷贝: 浅拷贝:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一

    2024年02月15日
    浏览(42)
  • 【C++初阶】模拟实现string的常见操作

    👦个人主页:@Weraphael ✍🏻作者简介:目前学习C++和算法 ✈️专栏:C++航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨ 为了方便管理代码,分两个文件来写: Test.cpp - 测试代码逻辑 string.h - 模拟实现 strin

    2024年02月12日
    浏览(53)
  • 【C++】深度剖析string类的底层结构及其模拟实现

    在上两篇中,我们已经学习了string类的一个使用,并且做了一些相关的OJ练习,相信大家现在对于string的使用已经没什么问题了。 那我们这篇文章呢,就来带大家对string进行一个模拟实现,这篇文章过后,有些地方大家或许就可以理解的更深刻一点。 那通过之前文章的学习我

    2023年04月17日
    浏览(107)
  • 【C++练级之路】【Lv.6】【STL】string类的模拟实现

    欢迎各位小伙伴关注我的专栏,和我一起系统学习C语言,共同探讨和进步哦! 学习专栏 : 《进击的C++》 关于 STL容器 的学习,我会采用 模拟实现 的方式,以此来更加清楚地了解其 底层原理和整体架构 。而string类更是有100多个接口函数,所以模拟实现的时候只会调重点和

    2024年01月18日
    浏览(50)
  • [C++] string类的介绍与构造的模拟实现,进来看吧,里面有空调

    C语言中,字符串是以’\\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合面向对象的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。 因此C++中,为了让我们更简单、方便

    2024年02月12日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包