yo!这里是STL::string类简单模拟实现

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

目录

前言

常见接口模拟实现

默认成员函数

1.构造函数

2.析构函数

3.拷贝构造函数

4.赋值运算符重载

迭代器

简单接口

1.size()

2.c_str()

3.clear()

操作符、运算符重载

1.操作符[]

2.运算符==

3.运算符>

扩容接口

1.reserve()

2.resize()

增删查改接口

1.push_back()

2.append()

3.运算符+=

4.insert()

5.erase()

6.find()

7.substr()

流插入&流提取

后记


前言

        我们知道,熟练使用STL是c++程序员的必备技能之一,今天我们来了解STL中的string类,即字符串类型,与c语言中的字符串类似,c++中只是对此做了封装,以及一些接口,基础的知识点这里不再赘述,全部接口功能包括但不限于默认成员函数、运算符操作符重载、reserve、push、pop、insert等等,更多接口介绍参考cplusplus.com/reference/string/string/ ,下面介绍一些常见或者主要接口的实现。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

常见接口模拟实现

  • 默认成员函数

1.构造函数

        如下图可知,库中string构造函数很多,适合接受不同参数列表的初始化方式,我们实现一种参数列表全缺省的构造函数,可以满足构造基本要求:

①传c类字符串就是用此字符串给类型初始化;

②不传就是用空字符串初始化对象,

注意:初始化时_size和_capacity都是初始化为字符串的长度,而new申请空间时多申请一个用来存放'\0'。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码:

String(const char* str = "")
	{
		_size = strlen(str);  //初始化列表有依赖关系时建议不用初始化列表,在大括号内初始化
		_capacity = _size;
		_str = new char[_capacity + 1];

		strcpy(_str, str);
	}

2.析构函数

        析构函数在库中只有下面一种,无参数无返回值,符合特性,我们知道,此类涉及申请内存,所以在析构函数中一定要释放内存,将变量置0,代码如下:

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码:

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

3.拷贝构造函数

        我们知道,拷贝构造函数是构造函数的一种,与普通构造函数写法类型,这是一种传统写法,代码如下,但是,这里讲一种现代写法,也是一种的复用的方法,就是定义一个临时对象,调用其自己的构造函数初始化,之后将初始化的成员交换给目标对象,而临时对象会自动调用析构函数释放,完美地将目标对象初始化完成。

代码:

//现代写法(老板思维)
String(const String& s)
	:_str(nullptr)
	,_size(0)
	,_capacity(0)
{
	String tmp(s._str);
	swap(_str, tmp._str);
	swap(_size, tmp._size);
	swap(_capacity, tmp._capacity);
}

//传统写法
//String(const String& s)
//{
//	_size = s._size;
//	_capacity = _size;
//	_str = new char[_capacity + 1];
//	strcpy(_str, s._str);
//}

4.赋值运算符重载

        库中的赋值运算重载如图,这里实现第一种,传统写法就是赋值_sieze、_capacity之后开空间传元素,考虑还用一下现代写法,去定一个临时对象调用拷贝构造初始化,再将其成员交换给目标对象,目标对象完美完成其初始化。

注意:考虑自己给自己赋值的情况

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码:

	//现代写法(老板思维)
	String& operator=(const String& s)
	{
		if (&s != this)
		{
			String tmp(s);
			/*delete[] _str;
			_str = nullptr;*/  //无需在此释放,交换给tmp后,出了作用域自动调用析构清理
			swap(_str, tmp._str);
			swap(_size, tmp._size);
			swap(_capacity, tmp._capacity);
		}
		return *this;
	}

    //传统写法
	//String& operator=(const String& s)
	//{
	//	if (&s == this)   //注意:自己给自己赋值的情况
	//		return *this;
	//	_size = s._size;
	//	_capacity = _size;

	//	/*delete[] _str;  //先释放的话万一new失败了就导致释放但未开辟空间成功
	//	_str = new char[_capacity + 1];*/
	//	
	//	char* tmp = new char[_capacity + 1];  //所以先开空间,开成功了再释放原空间
	//	delete[] _str;
	//	_str = tmp;
	//	strcpy(_str, s._str);
	//	return *this;
	//}
  • 迭代器

        迭代器有四种,这里实现两种以及其const型迭代器,string的迭代器就是原生指针(其他类型不一定),所以实现很容易,代码如下。 

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码:

	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;
	}
  • 简单接口

1.size()

        size()就是获取字符串字符个数,很简单不过多赘述,设置成const成员函数,是因为可以接受普通对象,也可以接受const对象。 

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

	size_t size() const
	{
		return _size;
	}

2.c_str()

        c_str()是获取c类型字符串,有一些场合可能需要传递指针型字符串,但是其是私有成员不能直接访问,此接口可以实现访问。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

	char* c_str() const
	{
		return _str;
	}

3.clear()

        clear()是清除字符串中字符,使其成为空串。 

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

	void clear()
	{
		_str[0] = '\0';
		_size = 0;
	}
  • 操作符、运算符重载

1.操作符[]

        操作符[]重载是很重要的重载,实现字符串对象可以像数组一样使用[]加下标访问,代码实现也很简单,注意普通对象和const对象权限不同,需要分开写。

代码: 

	char& operator[](size_t pos)  //普通对象,[]访问元素可读可写
	{
		assert(pos < _size);

		return _str[pos];
	}
	const char& operator[](size_t pos) const  //const对象,[]访问元素只可读
	{
		assert(pos < _size);

		return _str[pos];
	}

2.运算符==

        看过笔者上篇文章(http://t.csdn.cn/xT4nq)可以知道,先重载==、>,其他关系运算符可以复用它们方便的实现出来,不多赘述,不理解的可以翻翻看。

代码: 

    bool operator==(const String& s) const
	{
		return strcmp(_str, s._str) == 0;
	}

3.运算符>

        参考==运算符介绍。

代码: 

	bool operator>(const String& s) const
	{
		return strcmp(_str, s._str) > 0;
	}
  • 扩容接口

1.reserve()

        reverse()是预留空间,但不初始化,即只改变_capacity,传进想要预留的字符个数n,比_capacity大就会释放空间重新申请并拷贝元素。

注意:为string申请空间一定要多申请一个空间放'\0'

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

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

2.resize()

        resize()也是预留空间,并且初始化,即改变_capacity和_size,不传需要初始化的字符则默认是'\0',实现过程比reserve()多考虑一个赋值情况即可。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

    void resize(size_t n, char ch = '\0')
	{
		if (n > _size)
		{
			reserve(n + 1);
			for (size_t i = _size; i < n; i++)
			{
				_str[i] = ch;
			}
			_str[n] = '\0';
			_size = n;
		}
		else
		{
			_str[n] = '\0';
			_size = n;   //只需要改变size,不需要改变capacity
		}
	}
  • 增删查改接口

1.push_back()

        push_back()是在字符串结尾插入指定字符,首先检查是否需要扩容,需要扩容则要看是不是刚初始化的空字符串,空字符串默认先给4个地址空间,不是空字符串则扩容空间至二倍。

注意:

        ①莫忘_size加一;

        ②莫忘加'\0'在结尾。        

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

	void push_back(char ch)
	{
		if (_size == _capacity)
			reserve(_capacity ? _capacity * 2 : 4);
		_str[_size] = ch;
		_str[_size + 1] = '\0';
		_size++;
	}

2.append()

        append()是在字符串尾部插入一个字符串,实现逻辑很简单,可以直接复用push_back,但避免重复向操作系统申请空间,提前预留好空间用来插入字符,代码如下。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

	void append(const char* str)
	{
		size_t i = 0;
		size_t n = strlen(str);
		if (_size + n > _capacity)
			reserve(_size + n);   //要尽量少的重复申请空间
		for (i = 0; i < n; i++)
		{
			push_back(str[i]);
		}
	}

3.运算符+=

        +=运算符重载则是在字符串尾部既可以插入字符,也可以插入字符串,调用上面俩函数即可。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

	String& operator+=(char ch)
	{
		push_back(ch);
		return *this;
	}
	String& operator+=(const char* str)
	{
		append(str);
		return *this;
	}

4.insert()

        上面的插入操作只能作用在字符串尾部,而insert()函数是指定位置插入字符或者字符串,极端位置可以复用上面函数,普通位置需要移动元素,经历过c语言的学习,实现此功能并不难。

注意:代码中的标记点处是向后移动元素,注意移动过程中对下标的控制,不要越界访问。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

	String& insert(size_t pos, char ch)
	{
		assert(pos <= _size);
		if (_size == _capacity)
			reserve(_capacity ? _capacity * 2 : 4);
		if (pos == _size)
			push_back(ch);
		else
		{
			size_t end = _size + 1;
			while (end > pos)   //标记点
			{
				_str[end] = _str[end - 1];
				end--;
			}
			_str[pos] = ch;
			_size++;
		}
		return *this;
	}
	String& insert(size_t pos, const char* str)
	{
		size_t i = 0;
		size_t n = strlen(str);
		if (_size + n > _capacity)
			reserve(_size + n);
		if (pos == _size)
			append(str);
		else
		{
			size_t end = _size + n;
			while (end >= pos + n)   //标记点
			{
				_str[end] = _str[end - n];
				end--;
			}
			for (i = 0; i < n; i++)
			{
				_str[i + pos] = str[i];
			}
			_size += n;
		}
		return *this;
	}

5.erase()

        erase()则是删除指定位置指定长度的字符串,比插入的实现要简单,其中可以调用strcpy函数,npos是size_t类型的最大值,作为长度缺省值,实现不指定长度时默认是删除至结尾,注意删除完以后莫忘改变_size变量,其他并无难度。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

    void erase(size_t pos, size_t len = npos)
	{
		assert(pos < _size);
		if (_size - pos <= len)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			strcpy(_str + pos, _str + pos + len);
			_size -= len;
		}
	}

6.find()

        find()是查找指定字符或字符串第一次出现的位置下标,找不到返回npos,即无符号整型最大值,查找字符从头向后遍历查找即可,查找字符串调用strstr函数,注意此函数找到了是返回字符串地址,返回空是没找到,而find()是需要返回下标,注意控制。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

	size_t find(char ch, size_t pos = 0) const
	{
		assert(pos < _size);
		size_t i = 0;
		for (i = pos; i < _size; i++)
		{
			if (_str[i] == ch)
				return i;
		}
		return npos;
	}
	size_t find(const char* substr, size_t pos = 0) const
	{
		assert(substr);
		assert(pos < _size);
		char* ptr = strstr(_str + pos, substr);
		if (ptr == nullptr)
			return npos;
		return ptr - _str;
	}

7.substr()

        substr()是提取指定位置指定长度的子串,形成返回string类对象,复用+=运算符简化了实现逻辑,大体实现逻辑与其他函数并无不同,不多赘述。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

	String substr(size_t pos, size_t len = npos)
	{
		assert(pos < _size);
		String tmp;
		if (_size - pos <= len)
		{
			tmp += (_str + pos);
		}
		else
		{
			for (size_t i = 0; i < len; i++)
			{
				tmp += _str[pos + i];
			}
		}
		return tmp;
	}
  • 流插入&流提取

        在上一篇文章Date类型的简单实现中,使用友元的方式将流插入、流提取编写成了全局函数,因为当时是因为需要访问私有成员变量,那么这里我们发现,可以不需要访问私有成员变量,所以这里不在需要成为友元。

        对于流插入,定义一个临时数组,大小固定为32个元素的地址空间,循环从键盘获取字符插入,当临时数组满了之后,就整体插入到对象中,当获取到空格或者回车就停止,符合流插入的特性。

注意:

        ①临时数组没满时就遇到空格或回车的情况;

        ②这里使用istream类的get函数获取字符,不仅可以接收到普通字符也可以收到空格和回车,用以判断,而不直接使用cin<<,是因为cin输入过程中遇到空格或回车就停止了,接收不到它们。

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

yo!这里是STL::string类简单模拟实现,c++,开发语言,职场和发展,c语言,git,后端

代码: 

istream& operator>>(istream& in, String& s)   //无需成为友元函数,因为不需要访问私有成员
{
	s.clear();

	const size_t N = 32;
	char tmp[N];
	size_t i = 0;

	char ch;
	ch = in.get();
	while (ch != ' ' && ch != '\n')
	{
		tmp[i++] = ch;
		if (i == N - 1)
		{
			tmp[i] = '\0';
			s += tmp;
			i = 0;
		}
		ch = in.get();
	}
	tmp[i] = '\0';
	s += tmp;

	return in;
}

ostream& operator<<(ostream& out, const String& s)   //无需成为友元函数,因为不需要访问私有成员
{
	for (size_t i = 0; i < s.size(); i++)
	{
		out << s[i];
	}
	return out;
}

后记

        今天介绍了一些string常见常用接口的使用及底层实现,希望对于以上接口的使用可以熟练掌握,对于不常见的可以了解,知道有这样一个函数,在后面需要使用的时候,也可以查阅文档即时了解一下(cplusplus.com/reference/string/string/),对于以上接口的使用或者实现不懂的地方,欢迎可以在评论区评论或者私我,一起学习进步哦!文章来源地址https://www.toymoban.com/news/detail-613309.html


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

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

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

相关文章

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

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

    2024年02月15日
    浏览(30)
  • 【c++】:模拟实现STL模板中的string

        文章目录 前言 一.string的模拟实现 总结   上一篇文章我们详细介绍了STL中的string的一些常用的接口,这一篇文章我们将从底层实现string类,当然我们只是实现一些重要的,经常使用的接口,并且不是完全按照STL中的string去走的。   首先我们为了防止我们写的string类与库

    2024年01月20日
    浏览(33)
  • C++ stl容器string的底层模拟实现

    目录 前言: 1.成员变量 2.构造函数与拷贝构造函数 3.析构函数 4.赋值重载 5.[]重载 6.比较关系重载 7.reserve 8.resize 9.push_back,append和重载+= 10.insert 11.erase 12.find 14.迭代器 15.流插入,流提取重载 16.swap 17.c_str 18.完整代码+测试 总结: 1.成员变量 首先注意的就是_str,不能是const类型

    2024年04月23日
    浏览(29)
  • 【C++精华铺】10.STL string模拟实现

            STL(标准模板库)是一个C++标准库,其中包括一些通用的算法、容器和函数对象。STL的容器是C++ STL库的重要组成部分,它们提供了一种方便的方式来管理同类型的对象。其中,STLstring是一种常用的字符串类型。         STLstring是一个类,它封装了字符串的操作

    2024年02月09日
    浏览(34)
  • C++ STL学习之【string的模拟实现】

    ✨个人主页: Yohifo 🎉所属专栏: C++修行之路 🎊每篇一句: 图片来源 The key is to keep company only with people who uplift you, whose presence calls forth your best. 关键是只与那些提升你的人在一起,他们的存在唤起了你最好的一面。 string 本质上就是一个专注于存储字符的顺序表,使用起来

    2023年04月09日
    浏览(32)
  • 【C++初阶】STL详解(二)string类的模拟实现

    本专栏内容为:C++学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C++。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:C++ 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 注:为了防止与标准库当中的string类产生命名冲

    2024年02月05日
    浏览(39)
  • 【C++练级之路】【Lv.6】【STL】string类的模拟实现

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

    2024年01月18日
    浏览(37)
  • 【C++】:STL中的string类的增删查改的底层模拟实现

    本篇博客仅仅实现存储字符(串)的string 同时由于C++string库设计的不合理,我仅实现一些最常见的增删查改接口 接下来给出的接口都是基于以下框架: C++string标准库中,无参构造并不是空间为0,直接置为空指针 而是开一个字节,并存放‘\\0’ C++中支持无参构造一个对象后,直

    2024年02月05日
    浏览(40)
  • yo!这里是进程控制

    目录 前言 进程创建 fork()函数 写时拷贝  进程终止 退出场景 退出方法 进程等待  等待原因 等待方法 1.wait函数 2.waitpid函数 等待结果(status介绍) 进程替换 替换原理 替换函数 进程替换例子 shell简易实现 后记         学习完操作系统中进程部分的入门介绍之后,大家应该

    2024年02月09日
    浏览(29)
  • 【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改

    string使用文章   这里我们 实现常用的第四个string(const char* s)和析构函数     拷贝构造函数实现:   在堆上使用new为当前对象的成员变量_str分配内存空间,大小为s._capacity + 1字节,即字符串的容量加上一个结束符\\0的空间。   我们使用深拷贝而不是浅拷贝,

    2024年02月15日
    浏览(34)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包