C++类的模拟实现

📟作者主页:慢热的陕西人

🌴专栏链接:C++

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

本博客主要内容讲解了简单模拟实现string类

C++类的模拟实现

文章目录

  • C++类的模拟实现
    • @[toc]
    • Ⅰ.默认成员函数部分
    • Ⅱ. 常用成员函数的实现
    • Ⅲ. 运算符以及输入输出流的重载
    • Ⅳ. 迭代器实现

Ⅰ.默认成员函数部分

①构造函数

选择使用了带有缺省参数的构造函数写法:当没有传入字符串的时候,选择将string中的字符串初始化为空串。

初始化列表部分只对_size进行了初始化。

string(const char* str = "")
:_size(strlen(str))
{
	_capacity = _size == 0 ? 3 : _size;
	_str = new char[_capacity + 1];//+1因为要多以\0
	strcpy(_str, str);
}

②拷贝构造函数

拷贝构造函数是相当重要的,因为默认生成的拷贝构造函数只能实现浅拷贝,所以我们要自己来实现。

因为string类中涉及到了指针指向空间的问题所以在拷贝的时候也是需要新new一个空间出来的,这样就不会造成一份空间被析构两次的情况了

string(const string& s)
:_size(s._size)
,_capacity(s._capacity)
{
	_str = new char[_capacity + 1];
	strcpy(_str, s._str);
}

③析构函数

析构函数用于释放和清理string类实例化产生的空间。

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

Ⅱ. 常用成员函数的实现

  • c_str()

    用于返回string的字符串内容的函数。

    char* c_str()
    {
    	return _str;
    }
    
  • swap()

    用于交换两个string类的函数

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

    ①从pos位置开始在字符串寻找和ch相同的字符,并返回它第一次出现的位置

    ② 从pos位置开始在字符串寻找和str相同的字符串,并返回它第一次出现的位置

    size_t find(char ch, size_t pos = 0)
    {
    	assert(pos <= _size);
    	for (int i = pos; i < _size; i++)
    	{
    		if (_str[i] == ch)
    		{
    			return i;
    		}
    	}
    		return npos;
    }
    size_t find(const char* str, size_t pos = 0)
    {
    	assert(pos <= _size);
    			
    	char* p = strstr(_str + pos, str);
    	if (p == nullptr)
    	{
    		return npos;
    	}
    	else
    	{
    		return p - _str;
    	}
    }
    
  • clear()

    用于将string中的字符串清空的函数

    void clear()
    {
    	_str[0] = '\0';
    	_size = 0;
    }
    
  • reserve()

    用于改变string容量的函数,一般用于扩容。

    void reserve(size_t n)
    {
    	char* temp = new char[n + 1];
    	strcpy(temp, _str);
    	delete[] _str;
    	_str = temp; 
    	_capacity = n;
    }
    
  • insert()

    向字符串的pos位置插入字符或者字符串。

    string& insert(size_t pos, char ch)
    {
    	assert(pos <= _size);
    	if (_size + 1 > _capacity)
    	{
    		reserve(2 * _capacity);
    	}
    	错误问题会导致死循环
    	//size_t end = _size;
    	//while (end > pos)
    	//{
    	//	_str[end + 1] = _str[end];
    	//	--end;
    	//}
    
    	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)
    	{
    		assert(pos <= _size);
    		size_t len = strlen(str);
    		//挪动数据
    		size_t end = _size + len;
    		if (_size + len > _capacity)
    		{
    			reserve(_size + len);
    		}
    		while (end - len  + 1 > pos)
    		{
    			_str[end] = _str[end - len];
    			--end;
    		}
    		_size += len;
    		//拷贝数据
    		strncpy(_str + pos, str, len);
    		return *this;
    	}
    
  • erase()

    将字符串pos位置以及其之后的len长度的字符串都都删掉

    string& erase(size_t pos, size_t len = npos)
    {
    	if (len == npos || pos + len >= _size)
    	{
    		_str[pos] = '\0';
    		_size = pos;
    	}
    	else
    	{
    		strcpy(_str + pos, _str + pos + len);
    		_size -= len;
    	}
    	return *this;
    }
    
  • resize()

    改变字符串的大小,这里给了一个缺省参数,也就是当我们是要增大字符串的大小的时候可以给这个缺省值也可以不给。

    void resize(size_t n, char ch = '\0')
    {
    	if (n < _size)
    	{	
    		_size = n;
    		_str[n] = '\0';
    	}
    	else if(n > _size)
    	{
    		if (n > _capacity)
    		{
    			reserve(n);
    		}
    		int i = _size;
    		while (i < n)
    		{
    			_str[i] = ch;
    			++i;
    		}
    		_size = n;
    		_str[n] = '\0';
    		}
    }
    
  • pushback()

    向字符出串尾部插入字符

    void push_back(char ch)
    {
    	//if (_size + 1 > _capacity)
    	//{
    	//	reserve(2 * _capacity);
    	//}
    	//_str[_size] = ch;
    	//++_size;
    	//_str[_size] = '\0';
    	apend(&ch);
    	
    	//insert函数的复用
    	insert(_size, ch);
    }
    
  • apend()

    向字符串尾部追加字符串

    void apend(const char* str)
    {
    	//int len = strlen(str);
    	//if (_size + len > _capacity)
    	//{
    	//	reserve(_size + len);
    	//}
    	//strcpy(_str + _size, str);
    	//_size += len;
        //insert函数的复用
    	insert(_size, str);
    }
    

Ⅲ. 运算符以及输入输出流的重载

①运算符重载

bool operator<(const string& s) const
{
	return strcmp(_str, s._str) < 0;
}
bool operator==(const string& s) const
{
	return strcmp(_str, s._str) == 0;
}
bool operator>(const string& s) const
{
	return !(*this < s  && *this == s);
}
bool operator>=(const string& s) const
{
	return *this > s || *this == s;
}
bool operator<=(const string& s) const
{
	//这里给函数加上const才可以交换s和*this的值
	//因为不加const的话相当于是用s去调==的函数
	//但是因为s是一个const类型的,所以是权限的放大
	//所以结论就是对于不修改成员变量的函数最好加上const
	return *this < s || s == *this;
}
bool operator!=(const string& s) const
{
	return !(*this == s);
}
string& operator=(const string& s)
{
	if (this != &s)
	{
		//delete[] _str;
		//_str = new char[_capacity + 1];
		//strcpy(_str, s._str);
		//_capacity = s._capacity;
		//_size = s._size;

		char* temp = new char[_capacity + 1];
		strcpy(temp, s._str);
		delete[] _str;
		_str = temp;
		_capacity = s._capacity;
		_size = s._size;
	 }
	return *this;
}

②流插入和流输出重载

	ostream& operator << (ostream& out, const string& s)
	{
		for (auto ch : s)
		{
			out  << ch;
		}
		return out;
	}

	istream& operator >> (istream& in,  string& s)
	{
		s.clear();
		char ch = in.get();
		char buff[128];
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
				buff[i++] = ch;
				if (i == 127)
				{
						buff[127] = '\0';
						s += buff;
						i = 0;
				}	
			
				ch = in.get();
		}
		if (i != 0)
		{
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}

Ⅳ. 迭代器实现

这里只是实现了正向迭代器的实现

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

到这本篇博客的内容就到此结束了。
如果觉得本篇博客内容对你有所帮助的话,可以点赞,收藏,顺便关注一下!
如果文章内容有错误,欢迎在评论区指正

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

centos7部署FastDFS服务

一、安装需要的相关依赖 yum -y install make cmake gcc gcc-c 因为我的服务器已经安装了gcc&#xff0c;所以略去 使用gcc -v查看版本 yum -y install zip unzip 安装性能事件通知库 yum -y install libevent 安装nginx依赖 yum -y install libevent yum -y install zli…

OSCP-Fail(rsync、fail2ban提权)

目录 扫描 rsync 提权 扫描 rsync 基于nmap,确信将进一步研究rsync。 为此,将使用netcat使用的rsync枚举。 使用netcat,我们可以列出rsync托管的当前共享。 我们看到“fox”和“fox home

大数据管理中心规划设计方案(ppt可编辑)

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除。 统一汇聚 推动业务数据协同5 价值提炼 支撑精准服务与科学管理6 实时感知 辅助城市治理高效运行7 大数据资源平台目标体系规划11 建设目标与思路12 使能高效协同&#xff0…

PLM听过很多遍,却依旧不知道是什么?看完这篇你就懂

上周参加展会&#xff0c;很多客户在现场了解到e企拆图解决方案后&#xff0c;向我们咨询了很多问题&#xff0c;发现有几个名词经常被提及&#xff0c;比如PLM、PDM、BOM等。随着技术的爆炸发展&#xff0c;新的名词概念也与日俱增&#xff0c;对于这些名词&#xff0c;可能我…

Sa-Token源码简单阅读

一.权限登录模块包括几个基本子模块&#xff1a; 1.登录。 实现方式大致为&#xff1a;先检验用户名密码是否正确&#xff0c;如正确则在缓存中存入用户信息&#xff08;一般必须要有用户标识和访问token&#xff0c;或再加一些附加信息如用户的角色权限&#xff09;&#xf…

【unity细节】—(Can‘t add script)脚本文件无法拖拽到对象的问题

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏&#xff1a;unity细节和bug ⭐关于脚本文件无法拖拽到对象的问题⭐ 文章目录 ⭐关于脚本文件无法拖拽到对象的…

不得不说的结构型模式-装饰器模式

目录 装饰器模式是什么 下面是装饰器模式的一个通用的类图&#xff1a; 以下是使用C实现装饰器模式的示例代码&#xff1a; 下面是面试中关于桥接器模式的常见的问题&#xff1a; 下面是问题的答案&#xff1a; 装饰器模式是什么 装饰器模式是一种结构型设计模式&#xff…

苹果手机怎么看生产日期?参考方法在这!

案例&#xff1a;怎么查苹果手机买了几年&#xff1f; 【求助&#xff01;我从别人那里买了一部苹果手机&#xff08;非官方&#xff09;&#xff0c;怎么看这个手机用了几年&#xff1f;】 苹果手机作为一款高端手机&#xff0c;备受用户的喜爱。然而&#xff0c;许多用户不知…

Baumer工业相机堡盟工业相机如何通过BGAPI SDK获取每张图像的微秒时间和FrameID(C#)

BGAPI SDK获取图像微秒级时间和FrameID Baumer工业相机Baumer工业相机FrameID技术背景一、FrameID是什么&#xff1f;二、使用BGAPI SDK获取图像微秒时间和FrameID步骤 1.获取SDK图像微秒级时间2.获取SDK图像FrameIDBaumer工业相机使用微秒级时间和FrameID保存的用处Baumer工业…

全网唯一!Matlab世界顶尖艺术品配色包Rmetbrewer

想要绘制一幅颜色搭配合理、好看又不花哨的论文插图&#xff0c;该如何操作呢&#xff1f; 正所谓求其上者得其中&#xff0c;求其中者得其下。 那么&#xff0c;向高手借鉴思路&#xff0c;无疑是一种不落下乘的好策略。 而在色彩搭配领域&#xff0c;像莫奈、梵高这些世界…

操作系统原理 —— 进程有哪几种状态?状态之间如何切换?(七)

进程的五种状态 首先我们一起来看一下进程在哪些情况下&#xff0c;会有不同的状态表示。 创建态、就绪态 当我们刚开始运行程序的时候&#xff0c;操作系统把可执行文件加载到内存的时候&#xff0c;进程正在被创建的时候&#xff0c;它的状态是创建态&#xff0c;在这个阶…

三菱GX Works2梯形图程序分段显示设置的具体方法示例

三菱GX Works2梯形图程序分段显示设置的具体方法示例 大家平时在使用GX Works2进行梯形图程序编辑时,默认是一整段在一起,程序步数较多时查看起来不是那么方便,下面就和大家分享如何通过声明编辑来实现程序分段显示。 具体方法可参考以下内容: 如下图所示,打开GX Works2编…

DATAFAKER 使用方法记录

DATAFAKER 使用方法记录 win10 64位 Python 3.10.11 参考网址 datafaker的使用–详细教程 https://blog.csdn.net/A15517340610/article/details/105623103 https://github.com/gangly/datafaker python 版本 It is compatible with python2.7 and python3.4 也就是说 他…

案例2:Java图书商城系统设计与实现开题报告

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

使用nginx做WSS转为WS

HTTPS 是一种加密文本的超链接&#xff0c;所以需要证书&#xff0c;证书可以 使用域名&#xff0c;在腾讯云等服务商申请 https 证书&#xff0c;证书有 收费的和免费的&#xff0c;免费的有使用期限。 利用域名申请证书后&#xff0c;一般会有4中证书文件&#xff0c; .csr…

【Vue 基础】尚品汇项目-02-路由组件的搭建

项目路由说明&#xff1a; 前端的路由&#xff1a;Key-Value键值对 Key&#xff1a;URL&#xff08;地址栏中的路径&#xff09; Value&#xff1a;相应的路由组件 作用&#xff1a;设定访问路径&#xff0c;并将路径和组件映射起来&#xff08;就是用于局部刷新页面&#xff0…

前有谷歌的“生存指南”,后有金山系的“表格编程”,均登热榜

谷歌的“生存指南” 一位曾经在谷歌工作的工程师&#xff0c;干了一件了不起的事&#xff0c;花费了两年的时间&#xff0c;整理了一份“xg2xg”的清单。 原来这位离职的谷歌工程师为程序员编写了一份“厂外生存指南”&#xff0c;即使你从谷歌离职后&#xff0c;在这套“生存…

AlgoC++第六课:BP反向传播算法

目录 BP反向传播算法前言1. MNIST2. 感知机2.1 前言2.2 感知机-矩阵表示2.3 感知机-矩阵表示-多个样本2.4 感知机-增加偏置2.5 感知机-多个输出2.6 总结2.7 关于广播 3. BP4. 动量SGD5. BP示例代码总结 BP反向传播算法 前言 手写AI推出的全新面向AI算法的C课程 Algo C&#xf…

【三十天精通Vue 3】第十六天 Vue 3 的虚拟 DOM 原理详解

引言 Vue 3 的虚拟 DOM 是一种用于优化 Vue 应用程序性能的技术。它通过将组件实例转换为虚拟 DOM&#xff0c;并在组件更新时递归地更新虚拟 DOM&#xff0c;以达到高效的渲染性能。在 Vue 3 中&#xff0c;虚拟 DOM 树由 VNode 组成&#xff0c;VNode 是虚拟 DOM 的基本单元…

新黑马头条项目经验(黑马)

swagger (1)简介 Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务(API Documentation & Design Tools for Teams | Swagger)。 它的主要作用是&#xff1a; 使得前后端分离开发更加方便&#xff0c;有利于团队协作 接…