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

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

       前几篇文章中介绍了关于以及其相关函数的使用,为了更清楚的了解这些函数的作用,本篇文章通过模拟实现的方式来加深对于函数作用原理的理解。

目录

1. String的整体框架:

1.1 成员变量:

1.2 构造函数:

1.3 析构函数:

1.4 外部获取:

测试: 

2. 功能函数:

2.1 获取_size:

2.2 迭代器:

2.3 []访问及修改: 

测试:

2.4 打印函数:

3 对于对象的修改函数:

3.1 扩容函数:

3.2 插入函数:单个字符:

3.3 插入函数:字符串:

3.4 运算符重载+=:

测试:

3.5 在指定位置插入单个字符:

3.6 在指定位置插入字符串:

测试:

3.7  从指定位置开始向后删除任意长度字符串:

测试:

3.8 交换函数:

3.9 查询函数:查询单个字符:

3.10 查询函数:查询字符串:


1. String的整体框架:

1.1 成员变量:

       通过前面对于类的学习以及使用,不难得出,如果要模拟实现,则需要设置三个成员变量,即:_,_,_。因此,对于类的整体框架,可以有下面的代码表示:

namespace violent
{
	class string
	{
	public:


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

在有了整体的框架后,就需要在类中加入需要的成员函数

1.2 构造函数:

       在文章C++类与对象基础(7)-CSDNz中提到了初始化列表的概念,但是从上出给出的三个成员变量不难看出,三个变量全是内置类型,因此,对于内置类型的初始化,直接在函数内部进行,由于类主要针对于,字符串,因此,构造函数的参数也应该符合类型。

       在文章C++(9)——内存管理-CSDN博客提到了在C++(14)——string的模拟实现,C++,c++,开发语言中,管理内存的可以使用语言的两个函数,即.也可以使用C++(14)——string的模拟实现,C++,c++,开发语言中的两个关键字,即:。文章此处选择利用关键字来完成对于内存的管理。

对于如何获取参数中字符串的内容,可以利用来完成。

      对于三个关键字的取值,__可以利用字符串函数计算得出,对于开辟空间大小,需要注意,字符串的末尾会附带一个\,而函数计算的出的值并不会计算\,因此需要手动C++(14)——string的模拟实现,C++,c++,开发语言.具体代码如下:


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

但是,如果需要初始化的对象为空,上述函数并不能完成初始化。对于空的对象,可以看做对象中存储了一个\。可以通过缺省值的方式来完成针对于空对象的构造函数,即:

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

1.3 析构函数:

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

1.4 外部获取:

单独建立一个函数,用于返回指针_即可:

const char* c_str()
		{
			return _str;
		}

测试: 

      利用下方的代码,对上述函数的功能进行测试:

void test1string()
	{
		string s1;
		string s2("hello world");
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
	}

测试结果如下:

C++(14)——string的模拟实现,C++,c++,开发语言

2. 功能函数:

2.1 获取_size:

在遍历类型的对象时,经常会把对象中内容的长度,即_作为循环的结束,为了方便获取这个值,文章提供函数来实现。

size_t size()
		{
			return _size;
		}

2.2 迭代器:

之前的文章介绍迭代器的使用时,提到可以把迭代器看作指针(二者原理并不相同),因此,文章模拟实现迭代器也使用指针的方式,即:

iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

2.3 []访问及修改: 

       在之前的文章,在打印类型的对象时,会使用来完成对于对象的打印,并且,还可以完成对于对象中内容的修改。在介绍引用时,提到,引用返回相对于指针返回有两个有点,一是速度更快,二是可以修改返回值。在进行函数实现时,可以加上对于参数给出的位置是否合法的检查。因此,对于本小节的函数,实现如下:

char& operator[](size_t pos)
		{
			assert(pos <= _size);
			return _str[pos];
		}

测试:

通过下面的代码,完成对于上述函数功能的测试:

void test1string()
	{
       string s2("hello world");

		cout << "测试[]的访问功能;";
		for (size_t i = 0; i < s2.size(); i++)
		{
			cout << s2[i] << ' ';
			i++;
		}
		cout << endl;
		cout << "测试[]对于返回值的修改功能:";
		for (size_t i = 0; i < s2.size(); i++)
		{
			s2[i]++;
			cout << s2[i] << ' ';
		}

		cout << endl;
		cout << "测试迭代器访问:";
		string::iterator it1 = s2.begin();
		while (it1 != s2.end())
		{
			cout << *it1 << ' ';
			it1++;
		}
	}

运行结果如下:
C++(14)——string的模拟实现,C++,c++,开发语言

2.4 打印函数:

上述打印方式都需要额外编写,为了方便使用,直接将打印封装在一个函数,此处命名为_:

void print_str(const string& s)

需要注意,此时参数的类型与之前功能函数的类型并不匹配,因此需要根据前面的功能函数尽心修改,即:

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

		size_t size() const
		{
			return _size;
		}

对于迭代器和访问,需要额外提供两个函数,即:

typedef const char* const_iterator;

const_iterator begin() const
		{
			return _str;
		}

const_iterator end() const
		{
			return _str + _size;
		}

在对函数功能函数进行修改后,可以得出打印函数:
 

void print_str(const string& s)
	{
		for (size_t i = 0; i < s.size(); i++)
		{
			cout << s[i] << ' ';
		}

		string::const_iterator it2 = s.begin();

		while (it2 != s.end())
		{
			cout << *it2 << ' ';
			it2++;
		}


	}

测试效果如下:

C++(14)——string的模拟实现,C++,c++,开发语言

3 对于对象的修改函数:

(注:对于本部分内的函数实现原理与数据结构中链表的实现的文章一起学数据结构(3)——万字解析:链表的概念及单链表的实现-CSDN博客相同,因此不对原理进行过多介绍)

3.1 扩容函数:

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

3.2 插入函数:单个字符:

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';
		}

3.3 插入函数:字符串:

void append(const char* s)
		{
			size_t len = strlen(s);

			if (_size + len > _capacity)
			{
				reserve(_size + len);

			}
			strcpy(_str + _size, s);
			_size += len;
		}

3.4 运算符重载+=:

string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

		string& operator+=(const char* s)
		{
			append(s);
			return *this;
		}

测试:

测试代码如下:

void test2string()
	{
		string s2("hello world");
		cout << s2.c_str() << endl;

		s2 += 'x';
		cout << s2.c_str() << endl;

		s2 += "yyyyyy";
		cout << s2.c_str() << endl;
	}

运行结果如下:

C++(14)——string的模拟实现,C++,c++,开发语言

3.5 在指定位置插入单个字符:

在文章一起学数据结构(3)——万字解析:链表的概念及单链表的实现-CSDN博客中,详细介绍了如何实现此函数。在文章本部分,不进行详细的介绍,只给出图片来演示此过程:

C++(14)——string的模拟实现,C++,c++,开发语言

如上图可视:加入需要将字符从 插入,首先需要将位置及其后面的字符整体向后移动一位。即:
C++(14)——string的模拟实现,C++,c++,开发语言

C++(14)——string的模拟实现,C++,c++,开发语言

C++(14)——string的模拟实现,C++,c++,开发语言

C++(14)——string的模拟实现,C++,c++,开发语言

C++(14)——string的模拟实现,C++,c++,开发语言

代码如下:

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

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

3.6 在指定位置插入字符串:

原理与插入单个字符大致相同,代码如下:
 

void insert(size_t pos, const char* s)
		{
			assert(pos <= _size);
			size_t len = strlen(s);
			
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}

			int end = _size;
			while (end >= pos + len)
			{
				_str[end + 1] = _str[end];
				end--;
			}
			strncpy(_str + pos, s,len);
            _size += len;

		}

测试:

利用下方的代码对上述函数进行测试:

void test2string()
	{
		string s2("hello world");
		cout << s2.c_str() << endl;

		s2 += 'x';
		cout << s2.c_str() << endl;

		s2 += "yyyyyy";
		cout << s2.c_str() << endl;

		cout << endl << endl;
		s2.insert(0, 'a');
		cout << s2.c_str() << endl;

		s2.insert(3, "wwwww");
		cout << s2.c_str() << endl;
	}

运行结果如下:

C++(14)——string的模拟实现,C++,c++,开发语言

3.7  从指定位置开始向后删除任意长度字符串:

对于删除字符,需要分下面几种情况:

1.需要删除的字符长度大于等于

2.指定位置加上需要删除的字符长度大于_

对于上述两种情况,从位置向后全部删除。

对于其他情况,则根据需要删除的长度进行删除

对于第一种情况的删除,并不需要真正的将字符一个一个进行删除,只需要将位置的字符改为\,并且对_进行修改即可。

对于第二种情况的删除,加入指定为位置为,需要删除的字符串长度为。只需要将利用将C++(14)——string的模拟实现,C++,c++,开发语言位置之后的内容,从位置拷贝即可:

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

测试:

用下面给出的代码对上述函数进行测试:

void test3string()
	{
		string s3("hello world");

		s3.erase(5, 3);
		cout << s3.c_str() << endl;

		string s4("hello world");
		s4.erase(5, 100);
		cout << s4.c_str() << endl;	
	}

运行结果如下:
C++(14)——string的模拟实现,C++,c++,开发语言

3.8 交换函数:

C++(14)——string的模拟实现,C++,c++,开发语言

C++(14)——string的模拟实现,C++,c++,开发语言

C++(14)——string的模拟实现,C++,c++,开发语言

在网站中可以找到三种不同的交换函数,假如有两组不同类型的变量,即:

int a,b;
string s1,s2;

对于第一组变量,通过前面对于模板的了解得知其会去自动调用模板函数,对于第二组变量,在没有第一、二种的情况下会去调用模板函数,对于第一种和第二种,二者的区别是调用的形式不同,第一种的调用方法为:

swap(s1,s2);

对于第二种的调用方法为:

s1.swap(s2);

在有第一、二种函数的情况下,不会调用第三种,而是优先调用第一、二种。

对于第三种方式而言,由于代码对于类型的对象需要进行一次拷贝构造,因此效率较慢。对于第二种交换方式,是通过指针和来完成的,即交换两个对象的地址,并不交换其中的内容,即:
C++(14)——string的模拟实现,C++,c++,开发语言

C++(14)——string的模拟实现,C++,c++,开发语言

因此,为了速度,采用第二种交换方式,即:

void swap(string& s1)

 但是,在函数内部,并不能直接再次调用,即不能直接调用下面的代码:

void swap(string& s1)
		{
			swap(_str, s1._str);
			swap(_size, s1._size);
		    swap(_capacity, s1._capacity);
		}

按照上述代码的调用会引起歧义,因此,需要调用不同地方的,即:

void swap(string& s1)
		{
			std::swap(_str, s1._str);
			std::swap(_size, s1._size);
		    std::swap(_capacity, s1._capacity);
		}

3.9 查询函数:查询单个字符:

代码如下:

size_t find(char ch, size_t pos = 0)
		 {
			 assert(pos <= _size);

			 for(size_t i = pos; i < _size; i++)
			 {
				 if (_str[i] == ch)
				 {
					 return i;
				 }

			 }
			 return npos;
		 }

3.10 查询函数:查询字符串:


对于字符串的查询可以通过函数,对于函数的原理,可以从C语言——字符串和内存函数_c语言 指针 字符串 内存-CSDN博客进行查看。代码如下:

size_t find(const char* s, size_t pos = 0)
		{
			assert(pos <= _size);

			const char* str = strstr(_str + pos, s);
			if (str == nullptr)
			{
				return npos;
			}
			else
			{
				return str - _str;
			}
		}


 文章来源地址https://www.toymoban.com/news/detail-816157.html

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

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

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

相关文章

  • C++ 模拟实现string类

    目录 一、类的定义 二、初始化销毁 1、构造函数 2、辨析三种定义  3、析构函数 三、赋值  1、拷贝构造函数 2、赋值运算符 四、成员访问  operator[ ] 五、比较大小判断相等 六、容量操作  1、size() 2、reserve 3、push_back 4、append 5、加等运算符  6、C风格 7、insert 插入字符  插入

    2024年02月05日
    浏览(46)
  • C++: string的模拟实现

    注意:本文会用到strcpy,strstr,strncpy,strlen这几个函数 我会说明它们的功能和用法 如果大家想要彻底了解这几个函数 可以看一下我之前的博客: 征服C语言字符串函数(超详细讲解,干货满满) 比如说leetcode字符串相加这道题 既然string的模拟实现对我们这么重要 那就让我们一起踏上

    2024年02月04日
    浏览(36)
  • [C++]string及其模拟实现

    目录 string及其模拟实现::                                        1.构造函数                                        2.拷贝构造函数                                        3.赋值运算符重载                                        4.析构函数        

    2024年02月07日
    浏览(69)
  • C++:string类模拟实现

    1.获取容器大小(_size)和容量(_capacity) 2.扩容(reserve) 3.更改容器大小 1.尾插 2.指定位置插入 3.指定位置删除 4.清空 5.交换两个对象 1.截取子串 2.取得C格式字符串 3.赋值

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

    目录 string类成员变量 一.构造函数 二.析构函数 三.拷贝构造 四.size(),capacity() 五.operator [ ] 六. operator =  七.字符串比较  八.reserve() 九.push_back(),append() 十.operator+=  十一.insert()  十二.迭代器  十二.erase() 十三.swap()  十四.find() 十五.流提取,流输出 十六

    2024年02月14日
    浏览(37)
  • 【C++】——string的模拟实现

    前言: 在之前的学习中,我们已经对string类进行了简单的介绍,大家只要能够正常使用即可。但是在面试中,面试官总喜欢让学生自己 来模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。因此,接下来我将带领大家手动模拟实现一下

    2024年02月05日
    浏览(39)
  • 【C++】:string的模拟实现

    朋友们、伙计们,我们又见面了,本期来给大家解读一下有关string的模拟实现,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏: C语言:从入门到精通 数据结构专栏: 数据结构 个  人  主  页 : stackY、 C + + 专 栏   : C++ Linux 专

    2024年02月08日
    浏览(37)
  • C++模拟实现string类

    在C语言中,字符串是以’\\0’结尾的字符的集合,为了操作方便,C标准库中已经提供了一些str系列的库函 数,但是这些库函数与字符串是分离的,不符合面向对象编程的思想,而且底层空间需要用户自己管理,很可能会造成越界访问。 C++中对于string的定义为:typedef basic_s

    2024年02月13日
    浏览(70)
  • 【C++】string类模拟实现

    🚀 作者简介:一名在后端领域学习,并渴望能够学有所成的追梦人。 🚁 个人主页:不 良 🔥 系列专栏:🛸C++  🛹Linux 📕 学习格言:博观而约取,厚积而薄发 🌹 欢迎进来的小伙伴,如果小伙伴们在学习的过程中,发现有需要纠正的地方,烦请指正,希望能够与诸君一同

    2024年02月15日
    浏览(35)
  • 【C++】String类的模拟实现。

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

    2024年02月13日
    浏览(41)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包