C++类的模拟实现

news2024/12/23 0:21:25

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

🌴专栏链接: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;
		}

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Progress ThemeBuilder crack

Progress ThemeBuilder crack 自定义输入将覆盖自定义日期输入和下拉列表。 Fluent主题中的图表不应用系列颜色。 撤消重做操作会导致重复以前编辑过的变量。 拆分器折叠的拆分条模板错误。 ThemeBuilder是一个多功能工具&#xff0c;可以帮助您创建视觉样式&#xff0c;并将其…

数据分析入门之:如何快速安装使用Jupyter Notebook?

人生苦短&#xff0c;我用python 今天来给大家介绍一下关于Jupyter Notebook的用法 关于它的组成部分就先不在这里详细解说啦~ 毕竟我可太懂你们啦~ 文章太长就会吃灰的~ python 安装包资料:点击此处跳转文末名片获取 一、什么是Jupyter Notebook&#xff1f; 1. 简介 Jupy…

Atom 1.13版本带来的哪些改变?

Atom是GitHub基于Electron的开源文本编辑器&#xff0c;它的1.13版本 为用户和开发人员增加了许多新的特性和改进&#xff0c;包括一个基准工具&#xff0c;一个“重新打开项目”菜单选项和API&#xff0c;以及一个自定义按钮解析器&#xff0c;它可以把Chrome键盘事件映射为At…

PTA L1-092 进化论 (10 分)

在“一年一度喜剧大赛”上有一部作品《进化论》&#xff0c;讲的是动物园两只猩猩进化的故事。猩猩吕严说自己已经进化了 9 年了&#xff0c;因为“三年又三年”。猩猩土豆指出“三年又三年是六年呐”…… 本题给定两个数字&#xff0c;以及用这两个数字计算的结果&#xff0c;…

【c语言】函数的基本概念 | 函数堆栈调用原理

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…

【通知】CSDN学院:<华为流程体系课程> 正式上线啦!

目录 前言 适用人群 你将收获 课程介绍 前言 经过两个月的准备和短视频测试&#xff0c;这门介绍华为流程体系的课程就正式上线了。 虽然由于公开的原因&#xff0c;华为的发展受到了一定程度的影响&#xff0c;但是丝毫不妨碍企业、以及一些个人对学习华为的热情。 原因…

Java内存模型详解

Java内存模型 Java内存模型(Java Memory Model)是Java虚拟机规范定义的&#xff0c;用于屏蔽因不同程序/硬件/操作系统上内存访问的差异&#xff0c;确保程序运行与设计一致&#xff0c;Java内存模型定义了Java虚拟机在计算机内存中的工作方式&#xff0c;确定了在共享内存系统…

通过SSH实现Linux与Windows之间的文件互传

目录 一 序言 二 准备工作 三 Windows端操作命令&#xff0c;实现文件互传 四 Linux端操作命令&#xff0c;实现文件互传 五 总结 一 序言 Linux和Linux以及Windows和Windows之间的文件共享互传&#xff0c;大家应该接触的都比较多&#xff0c;无非就是两种方式&#xff…

【C++类和对象】类和对象(上) {初识面向对象,类的引入,类的定义,类的访问限定符,封装,类的作用域,类的实例化,类对象模型,this指针}

一、面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠对象之间的交互完成。…

1.2和1.3、GCC

1.2和1.3、GCC 1.2和1.3、GCC1.2.1、什么是GCC1.2.2、编程语言的发展1.2.3、GCC工作流程1.2.4、gcc和g的区别1.2.5、GCC常用参数选项实际操作①接下来进行预处理操作&#xff08;test.c为需要预处理的源代码&#xff0c;test.i为要生成的目标代码&#xff09;②汇编操作&#x…

iOS--SDWebImage源码

文章目录 前言它提供了UIImageView的一个分类&#xff0c;支持从网路上下载且缓存图片&#xff0c;并设置图片到对应的UIImageView控件或者UIButton控件。 SDWebImage简介官方图解主序列图&#xff08;Main Sequence Disagram&#xff09;顶层API图&#xff08;Top Level API D…

XLA IR:HLO、LHLO、MHLO和LMHLO

XLA IR&#xff1a;HLO、LHLO、MHLO和LMHLO HLOLHLOMHLOLMHLOXLA IR 总结HLO->LMHLO xla基本编译流程如下&#xff1a; HLO Optimization: 硬件无关优化和硬件相关优化LHLO Codegen: 算子向量化和llvmir的生成HLO&LHLO是XLA-HLO&#xff1b;MHLO&LMHLO是MLIR-HLO&…

队列的基本操作(C语言链表实现)初始化,入队,出队,销毁,读取数据

文章目录 前言一、队列基本变量的了解二、队列的基本操作2.1队列的初始化&#xff08;QueueInit&#xff09;2.2入队&#xff08;QueuePush&#xff09;2.3判断是否为空队&#xff08;QueueEmpty&#xff09;2.4出队&#xff08;QueuePop&#xff09;2.5队列的队头数据&#xf…

分享BigDecimal金额计算的4种方式

基本介绍 金额计算这块通常都是基于2位小数的四舍五入&#xff0c;如果是自己的系统内部功能金额位数一般都是固定的&#xff0c;在正常的加减乘除运算逻辑都是保留同样位数的&#xff0c;但是乘法和除法相对比较特殊&#xff0c;在计算小数的部分可能会计算出更多位数的小数点…

【微服务】搭建Consul集群服务和Consul配置中心

文章目录 一、传统配置文件的弊端二、微服务配置中心三、主流的配置中心四、Consul 配置操作1.添加配置信息2.获取配置信息 五、单点服务器Consul集群 一、传统配置文件的弊端 静态化配置&#xff0c;例如env文件配置文件无法区分环境配置文件过于分散历史版本无法查看 配置中…

5.5、线程池同步机制类封装及线程池实现

代码地址 5.5、线程池同步机制类封装及线程池实现 1.线程池2.代码实现①锁Ⅰ、locker.hⅡ、locker.cpp ②条件变量Ⅰ、cond.hⅡ、cond.cpp ③信号量Ⅰ、sem.hⅡ、sem.cpp ④线程池Ⅰ、threadpool.hⅡ、threadpool.cpp 1.线程池 线程池是由服务器预先创建的一组子线程&#xf…

行为识别预警系统 opencv

行为识别预警系统通过pythonopencv网络模型技术&#xff0c;行为识别预警系统对现场画面中人的行为进行智能分析&#xff0c;发现违规行为自动抓拍告警&#xff0c;同步回传后台存档提醒值班人员及时处理。OpenCV的全称是Open Source Computer Vision Library&#xff0c;是一个…

CVE漏洞复现-CVE-2019-5736 Docker逃逸

CVE-2019-5736 Docker逃逸 Docker是什么&#xff1f; Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有…

JAVA实现AES加密、解密附代码

大家好&#xff0c;今天我们一起来学习 Java中的加密解密技术&#xff0c; java是一门面向对象的语言&#xff0c;使用它的开发人员都是非常聪明的人&#xff0c;他们对数据的安全性要求很高。在实际的应用中&#xff0c;我们都需要对数据进行加密、解密处理&#xff0c;这在 j…

【数据结构】第十三站:排序(上)

本文目录 一、排序概念二、插入排序1.插入排序的基本思想2.算法实现3.时间复杂度分析 三、希尔排序1. 希尔排序的思想2.希尔排序的代码实现3.希尔排序和插入排序的性能测试比较4.希尔排序的时间复杂度 四、直接选择排序1.基本思想2.直接选择排序的步骤3.直接选择排序的代码实现…