c++学习之string实现

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

字符串 - C++引用 (cplusplus.com)这里给出标准官方的string实现,可以看到设计还是较为复杂的,有成员函数,迭代器,修饰符,容量,元素访问,字符串操作等,将字符尽可能的需求都设计出来,我们这里实现string中比较常用且重要的。

成员变量

private:
	char* _str;
	size_t _size;
	size_t _capacity;
public:
	const static size_t npos;//声明一个npos 表示返回找不到的下标 或从-1的下一个开始寻找

目录

1.迭代器实现

2.成员函数

空构造

 有参构造

 拷贝构造

析构

 重载=

3.字符串操作

c_str

 find 

 substr

5.修饰符

push_back

 append

 operator+=

insert

 erase

6.容量

reserve

size

capacity

resize 

7.元素访问

重载下标引用操作符

8.运算符重载

重载<

重载==

重载<=

重载>

重载>=

重载!=

重载输入流

重载输出流


1.迭代器实现

这里我们实现了常量迭代器与正常的迭代器,反向迭代器并未实现。对于string这里的迭代器我们可以看到本质上是一个char *类型的指针,在某些地方可能不是指针,且它的用法也是与指针如出一撤。这里对于反向迭代器后面再实现。

    typedef char* iterator;//迭代器
	const typedef 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;
	};

在这里, 我们将char*定义为一个新的类型,并且给出它的成员函数,也就是迭代器的各个位置,从而实现。利用迭代器我们可以对他进行遍历:

Mystring::iterator it = str1.begin();
	while (it != str1.end())
	{
		cout << *it ;
		++it;
	}

 //范围for
  for (auto tmp : str1)
 {
	 cout << tmp ;
 }

 同时其实本质上范围for的底层就是利用迭代器实现的,编译器在遇到范围for这样的写法时就会将这一段代码替换成下面迭代器实现的这样的遍历。

2.成员函数

空构造

实际上并不需要实现,我们这里给出它的实现,是了解对于空字符串的构造函数,虽说是空字符串,但不可直接赋值nullptr,否则后面实例化对象调成员函数时就是解引用空指针,空字符串,故这里会报错,实际上实现会给几个字节空间,放\0

Mystring():_str(new char[1]),_capacity(0),_size(0)
	{
	

	}

 有参构造


	//有参构造
	Mystring(const char* str="") : _size(strlen(str)), _capacity(_size)//缺省值直接给"",不给"\0",原先就有\0
	{
		//注意这里的字符串利用深拷贝,且初始化顺序遵循声明顺序
		_str = new char[_capacity + 1];//多开一个给\0
		strcpy(_str, str);
	}
	

 拷贝构造

还是老问题,直接的赋值会造成两次析构,故这里需要进行深拷贝。

//拷贝构造
	//之前讲过,浅拷贝会析构两次,深拷贝解决
	Mystring(const Mystring& s)
	{
		_str = new char[s._capacity + 1];
		memset(_str, 0, s._capacity);
		strcpy(_str, s._str);
		this->_size = s._size;
		this->_capacity = s._capacity;
	}

析构

释放及初始化

//析构
	~Mystring()
	{
		delete [] _str;
		_str = nullptr;
		_capacity = _size = 0;
	}

 重载=

// 赋值重载
	Mystring& operator=(const Mystring& s)
	{
		if (*this != s)
		{
			char* temp = new char[s._capacity+1];
			strcpy(temp, s._str);
			delete []_str;
		    _str = temp;
			this->_size = s._size;
			this->_capacity = s._capacity;
		}
		return *this;
	}

 这里的赋值重载区分拷贝构造:

用现有对象初始化定义的对象---------拷贝构造

用现有对象赋值给现有对象------------赋值

3.字符串操作

这里实现几个比较重要的,常用的。

c_str

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

 find 

这里给出了两种实现,字符寻找与字符串寻找

//寻找某个字符,返回其下标位置
	size_t find(char ch,size_t pos=0)
	{
		for (size_t i = pos; i < _size; i++)
		{
			if (ch == _str[i])
			{
				return i;
			}
		}
		return npos;//找不到,返回-1
	}
	//寻找某个字符串,返回其相同的个数
	size_t find(const char* ch, size_t pos = 0)
	{
	  //暴力匹配
		const char* tmp = strstr(_str+pos, ch);
		if (tmp!= nullptr)
		{
			return tmp - _str;//指针相减,找到个数
		}
		else
		{
			return npos;
		}
		
	}
	

 substr

//从pos位置处取n个字符,或n到 npos
	Mystring substr(size_t pos, size_t len=npos)
	{
		assert(pos < _size);
		Mystring s;
		size_t end = pos + len;
		if (len == pos || len + pos >= _size)
		{
			len = _size - len;
			end = _size;
		}
		s.reserve(len);
		for (size_t i = pos; i <pos+len; i++)
		{
				s += _str[i];//这里利用重载后的+=,本质上就是尾插
		}
		return s;
	}

5.修饰符

push_back


	//尾插字符
	void push_back(char ch)
	{
		//尾插的操作很简单,但是要考虑到扩容的问题
		if (_size == _capacity)
		{
			reserve(_capacity=0?4:_capacity * 2);//为了避免空间是0,扩容失败
		}
		_str[_size] = ch;
		++_size;
		_str[_size] = '\0';
	}
	

 append

//尾插字符串
	void append(const char*ch)
	{
		size_t num = strlen(ch);
		if (num + _size > _capacity)
		{
			reserve(num + _size);
		}
		strcpy(_str + _size, ch);
		_size += num;
		//注意这里直接运用strcpy拷贝过来,连同\0一起,之后变为新大小
	}

 operator+=

这里重载的+=是利用了尾插的实现,故也作为字符串修饰

也是两种实现,+=字符或字符串

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

insert

 也是有两种实现方式

注意注释的提示:若这里想要进行头插,此时end>=0。只有当end--到负数才停止,而size_t 无法去判断正负数,程序崩溃,解决方法,将类型转换为int ,或者修改后移顺序,_str[end] = _str[end-1];去掉条件=。

其次就是对于扩容需要考虑空间为0的情况。

//某个位置插入字符
	void insert(size_t pos,char ch)
	{
		assert(pos < _size);
		if (_size == _capacity)
		{
			reserve(_capacity = 0 ? 4 : _capacity * 2);//为了避免空间是0,扩容失败
		}
		int end = _size;
		//pos位置处后移
		while (end>=(int)pos)
		{
			//后移
			_str[end + 1] = _str[end];
			--end;
		}
		//插入
		_str[pos] = ch;

	}
	//某个位置插入字符串
	void insert(size_t pos,char *ch)
	{
		
		size_t len = strlen(ch);
		if (_size +len>_capacity)
		{
			reserve(_capacity = 0 ? 4 : _capacity * 2);//为了避免空间是0,扩容失败
		}
		size_t end = _size;
		//pos位置处后移
		while (end >= pos)
		{
			//后移
			_str[end + len] = _str[end];
			--end;
		}
		//插入
		strncpy(_str+pos, ch,len);
		_size += len;
	}

 erase

删除pos位置后的npos个字符,这里的npos给的是缺省值,再没参数的情况下为-1,也就是pos后的全部删除。

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

	}

6.容量

reserve

//扩容
	void reserve(size_t n)
	{
		if (n > _size)
		{
			char* tmp = new char[n + 1];//这里还是留一个\0位置
			strcpy(tmp, _str);
			delete[]_str;
			_str = tmp;
			_capacity = n;
		}
		
	}

size

//返回大小
size_t size()const
	{
		return _size;
	}

capacity

//返回容量
size_t capacity()const
	{
		return _capacity;
	}

resize 

//初始化大小为n,且可以赋值之后的
	void resize(size_t n,char c='\0')
	{
		if (n <= _size)
		{
			//删除
			_str[n] = '\0';
			_size = n;
		}
		else
		{
			//扩容
			reserve(n);
			//初始化值
			while (_size < n)
			{
				_str[_size] = c;
				_size++;
			}
			//末尾给\0
			_str[_size] = '\0';
		}
	}

7.元素访问

重载下标引用操作符

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

8.运算符重载

对于这里的比较运算符,通过实现<与==,再取反实现> ,>=,!=.文章来源地址https://www.toymoban.com/news/detail-679849.html

重载<

bool operator<(const Mystring &s1)
	{
		return strcmp(this->_str, s1._str) <0;
	}

重载==

bool operator==(const Mystring& s)
	{
		return strcmp(this->_str, s._str) == 0;
	}

重载<=

bool operator<=(const Mystring& s)
	{
		return *this < s || *this == s;//由于<与=已实现,直接用
	}

重载>

bool operator>(const Mystring& s)
	{
		return !( *this <=s) ;//取反
	}

重载>=

bool operator>=(const Mystring& s)
	{
		return !(*this < s);//取反
	}

重载!=

bool operator!=(const Mystring& s)
	{
		return!(*this==s);
	}

重载输入流

//流插入
istream& operator>>(istream& in, Mystring& s)
{
	char ch;
	ch = in.get();//一个个拿字符,包括空格与\n
	while (ch != ' ' && ch != '\n')
	{
		s += ch;
		ch = in.get();
	}
	return in;
}

重载输出流

//流提取
ostream& operator<<(ostream& out, const Mystring& s)
{
	for (size_t i = 0; i < s.size(); i++)
	{
		out << s[i];
	}
	return out;
}

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

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

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

相关文章

  • C++学习 --string

    目录 1, 什么是string 2, 创建string 2-1,普通创建  2-2, 拷贝构造创建 2-2-1, 整体拷贝 2-2-2, 部分拷贝 2-3, 指定长度创建 3, 赋值(assign) 3-1, 拷贝构造赋值 3-1-1, 整体赋值 3-1-2, 部分赋值 3-2, 指定长度赋值 4, 拼接 4-1, 拼接(+) 4-2, 拼接(append) 4-2-1, 整体拼接 4-2-2,

    2024年02月04日
    浏览(59)
  • 【C++】对于string的学习

    本篇文章针对C++中的string做一些详细的介绍和学习,并且会包含一些关于STL的介绍 注意: 本篇文章只包含基础知识 STL是标准模板库的一个缩写,全称是Standard Template Library C++中定义了一种类,为string,存放在头文件string中 存放C语言风格字符串的头文件是cstring,也就是以’

    2024年02月10日
    浏览(46)
  • c++ 学习之 类的权限访问修改学习

    当分析这段代码时,涉及的主要概念包括: 成员函数和成员变量: 在类 person 中,有三个成员函数:set_name、get_name 和 fun,以及两个成员变量:name 和 age。 成员函数用于操作和访问成员变量,可以在类内部定义其实现。 成员变量存储类的状态和数据。 访问权限: set_name、

    2024年02月10日
    浏览(33)
  • NRCE 二级C语言开发环境:Microsoft Visual C++ 2010 学习版下载

    Microsoft Visual C++ 2010 学习版 2022版考纲 网盘链接:点击下载 提取码:siyy 网盘地址下载太慢可以到:官网下载 下载完成后,是一个iso镜像文件,点击上方装载。 装载完成后,可以看到计算机处有个无穷图标的DVD驱动器 现在就可以去到你安装磁盘目录下的IDE目录(星号中间的

    2024年02月11日
    浏览(57)
  • C++学习 Day15(string类)

    C 语言中,字符串是以 \\\'\\0\\\' 结尾的一些字符的集合,为了操作方便, C 标准库中提供了一些 str 系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP 的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。 在 OJ 中,有关字符串的题目基本以 stri

    2024年02月08日
    浏览(42)
  • 【C++】手撕string(string的模拟实现)

    手撕string目录: 一、 Member functions 1.1 constructor 1.2  Copy constructor(代码重构:传统写法和现代写法) 1.3 operator=(代码重构:现代写法超级牛逼) 1.4 destructor 二、Other member functions 2.1 Iterators(在string类中,迭代器基本上就是指针) 2.1.1 begin() end() 2.1.2  范围for的底层

    2024年02月08日
    浏览(45)
  • 【C++初阶】string 类的认识与学习

      在学习string类之前,先在这里推荐2个好用的网站,可以用来查阅C++的相关知识 https://cplusplus.com https://en.cppreference.com/w/ 上面的是非官方的,下面的官方的,但是个人感觉还是上面的好用。 简单来说, string 是C++中用来管理字符串的类。 他有很多接口,大致分为: 1.string类

    2024年02月09日
    浏览(49)
  • c++学习:STL之string类初识

    目录 1.关于STL 1.什么是STL 2.STL的六的组件 2.关于string类的学习 1.为何学习string类 2.何为string类 3.string类对象的构造 4.容量操作  5.元素访问的操作 6.迭代器(Iterators) 7.修改类的操作  8.字符串操作 STL(standard template library-标准模板库):是c++标准库的重要组成部分,不仅是一

    2024年02月03日
    浏览(70)
  • C++学习之list的实现

    在了解学习list实现之前我们首先了解一下关于迭代器的分类: 按功能分类: 正向迭代器    反向迭代器 const正向迭代器  const反向迭代器 按性质分类: 单向迭代器      只能++    例如单链表  双向迭代器     可++,也可--     例如双链表 ,map和set  随机迭代器     可

    2024年02月09日
    浏览(34)
  • 【C++初阶】STL之学习string的用法

    STL是C++的标准模板库 ,里面包含了许多 算法和数据结构 ,例如我们熟悉的顺序表、链表、栈和队列以及一些常见的算法等等,编程者想使用这些就可以直接从库中调用,不必再自己造轮子了。 下面为STL内容的一张图: 接下来,我们要学习STL中的string。 string 是C++的一个类模

    2024年02月04日
    浏览(46)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包