C++实现一个自定义字符串类(string)

news2024/12/23 22:05:55

本博客将详细介绍如何在C++中实现一个自定义的字符串类 string,这个类模仿了标准库中 std::string 的关键功能。这个过程将涵盖从声明到定义的每一步,重点介绍内存管理、操作符重载以及提供一些关键的实现细节。

首先:我们采用函数的声明与定义分离

目的是为了增加代码的可维护性以及提高效率:

1.在vs中,如果我们不实现声明与定义分离,那么编译器会默认认为你当前的函数是内联函数

:内联函数是一种编译器指令,它告诉编译器尝试在每个调用点展开函数体,而不是进行常规的函数调用。 

也就是说每次调用时会直接展开代码,这只适合一些代码量很小但调用机器频繁的函数。所以我们采用函数的声明与定义分离也可以进一步的优化效率。

2.函数声明与定义分离的注意事项和特点

  1. 改善编译依赖性:将函数声明放在头文件中,而将实现(定义)放在源文件中,可以减少编译时的依赖关系。当实现改变时,只需重新编译该源文件及其直接依赖,而不需要重新编译包含头文件的所有文件。

  2. 封装:通过隐藏实现细节,可以保护数据和实现,减少模块间的耦合。这符合封装的面向对象原则,有助于维护和扩展。

  3. 链接考虑:在多个源文件中分散定义的函数只有在最终链接时才会解析。这种分离确保了更好的模块化和错误隔离,尤其是在大型项目中。

  4. 避免多重定义:如果在多个源文件中包含相同的函数定义而未进行适当的静态或内联标记,将导致链接错误。正确的声明和定义分离有助于避免这种问题。

类声明和成员变量

首先,我们需要在 my_string 命名空间中定义字符串类的结构。这包括成员变量和函数的声明

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <assert.h>
#include <string.h>

namespace my_string {
	class string {
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
	public:
		const_iterator begin() const;
		const_iterator end() const;
		iterator begin();
		iterator end();
		const char* c_str() const;
		void earse(size_t pos, size_t len = npos);
		void insert(size_t pos, char ch);
		void insert(size_t pos, const char* str);
		void swap(string& s);
		void clear();
		void pushback(char ch);
		void append(const char* str);
		void reserve(size_t n);
		void resize(size_t n, char ch = '\0');
		size_t size()const;
		size_t capacity()const;
		size_t find(char ch, size_t pos = 0)const;
		size_t find(char* sub, size_t pos = 0)const;
		string(const char* str = "");
		string(const string& str);
		~string();
		string& operator=(string tmp);
		string& operator+=(const char* str);
		string& operator+=(char ch);
		bool empty()const;
		const char& operator[](size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;
	public:
		static const int npos;
	};
	
	

在定义成员变量时我们采用缺省值来增加安全性。

经典的string类问题

浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来 。如果 对象中管理资源 ,最后就会 导致多个对象共 享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为为 有效,所以当继续对资源进项操作时,就会发生发生了访问违规

深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情 况都是按照深拷贝方式提供。

 也就是说我们如果不显示构造就会用默认的拷贝构造函数,就会出错!

 构造函数和析构函数实现

构造函数初始化字符串,并为字符数组分配内存。我们同时提供了拷贝构造函数和析构函数以处理资源管理:

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



string::string(const string& str)
{
	string tmp(str._str);
	swap(tmp);
}



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

动态内存管理实现

对于内存管理,我们实现了 reserveresize 方法来处理内存分配和调整大小的需求:

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

void string::resize(size_t n, char ch) {
    if (n > _size) {
        reserve(n);
        std::fill(_str + _size, _str + n, ch);
        _size = n;
    }
    _str[_size] = '\0';
}

操作符重载

操作符重载使得字符串类的对象能以类似于原生数据类型的方式使用:

string& string::operator=(string tmp) {
    swap(tmp);
    return *this;
}

bool operator==(const string& s1, const string& s2) {
    return strcmp(s1.c_str(), s2.c_str()) == 0;
}

std::ostream& operator<<(std::ostream& out, const string& s) {
    out << s._str;
    return out;
}

 实现自定义迭代器

迭代器提供了几种操作,如递增 (++), 递减 (--), 解引用 (*), 等。在我们的例子中,由于使用了原始指针作为迭代器,这些操作已经由指针的自然行为直接支持


		//这里我们手搓一个迭代器
		typedef char* iterator;
		typedef const char* const_iterator;
		const_iterator begin() const
		{
			return _str;
		}

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

		iterator end()
		{
			return _str + _size;
		}

 支持范围 for 循环

在C++定义中,范围for的底层实现是迭代器,所以哪怕我们要自定义使用范围for

我们就必须手动实现一个一模一样的迭代器这样就可以使用了

实现流插入和输出操作

在自定义实现流插入时,我们发现只能从右边传递给左边,但左边默认是*this,此时如果还是右边传递给左边,那不就成立 cout 传递给 *this 了,道反天罡!所以我们采取定义全局函数,将参数变成两个自定义的就可以解决,由于cout 是ostream流里的  cin是istream流里的所以返回类型也是对应的流类型

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

std::istream& operator>>(std::istream& in, string s)
{
	s.clear();
	char ch;
	//in >> ch;  //不能用下标 还没开孔加呢
	// 
	ch = in.get();
	char buff[128];
	size_t i = 0;

	//cin 和 scanf读不到空格
	//C语言用getchar 
	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;
}
总结

以上就是如何在C++中从头到尾实现一个自定义的 string 类。我们不仅关注了如何实现基础功能,还涉及了如何通过操作符重载提高类的可用性,以及如何确保类在处理动态内存时的安全和效率。通过这种方式,我们能更深入地理解标准 std::string 类的内部工作机制,并能在需要时为自己的应用定制特定的行为。

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

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

相关文章

python--字符串对象和

1、找出10000以内能被5或6整除&#xff0c;但不能被两者同时整除的数&#xff08;函数&#xff09; def Divisible_by_5_6(x:int)->list:arr[]for i in range(1,x1):if (i % 5 0 or i % 6 0 ):if i % 5 0 and i % 6 0:continue #利用continue跳过能被5和6整除的数else:a…

Spring Boot 学习(4)——开发环境升级与项目 jdk 升级

各种版本都比较老&#xff0c;用起来也是常出各样的问题&#xff0c;终于找到一个看来不错的新教程&#xff0c;是原先那个教程的升级。遂决定升级一下开发环境&#xff0c;在升级遇到一些问题&#xff0c;摸索将其解决&#xff0c;得些体会记录备查。 最终确定开发环境约束如下…

ActiveMQ 01 消息中间件jmsMQ

消息中间件之ActiveMQ 01 什么是JMS MQ 全称&#xff1a;Java MessageService 中文&#xff1a;Java 消息服务。 JMS 是 Java 的一套 API 标准&#xff0c;最初的目的是为了使应用程序能够访问现有的 MOM 系 统&#xff08;MOM 是 MessageOriented Middleware 的英文缩写&am…

QLoRa 低秩分解+权重量化的微调

QLoRa的核心思想是首先使用低秩分解技术降低参数的数量&#xff0c;然后对这些低秩表示的参数应用量化技术&#xff0c;进一步减少所需的存储空间和计算量。 https://arxiv.org/abs/2305.14314 低秩分解 低秩分解&#xff08;Low-Rank Factorization&#xff09;&#xff1a;…

Elasticsearch初步了解学习记录

目录 前言 一、ElasticSearch是什么&#xff1f; 二、使用步骤&#xff08;python版&#xff09; 1.引入包 2.连接数据库 3.创建索引 4.写入数据 5.查询数据 三、相关工具介绍 1.ES浏览器插件 总结 前言 随着数据量的不断增加&#xff0c;传统的查询检索在速度上遇…

Android使用shape属性绘制边框内渐变色

目录 先上效果图实现方法shape属性介绍代码结果 先上效果图 这是使用AndroidStudio绘制的带有渐变色的边框背景色 实现方法 项目中由于UI设计需求&#xff0c;需要给按钮、控件设置带有背景色效果的。以下是UI效果图。 这里我们使用shape属性来绘制背景效果。 shape属性介…

机器学习-09-图像处理02-PIL+numpy+OpenCV实践

总结 本系列是机器学习课程的系列课程&#xff0c;主要介绍机器学习中图像处理技术。 参考 【人工智能】PythonOpenCV图像处理&#xff08;一篇全&#xff09; 一文讲解方向梯度直方图&#xff08;hog&#xff09; 【杂谈】计算机视觉在人脸图像领域的十几个大的应用方向&…

清远某国企IBM服务器Board故障上门维修

接到一台来自广东清远市清城区某水利大坝国企单位报修一台IBM System x3650 M4服务器无法开机的故障&#xff0c;分享给大家&#xff0c;同时也方便有需要的朋友能及时找到我们快速解决服务器问题。 故障服务器型号&#xff1a;IBM System x3650 M4 服务器使用单位&#xff1a;…

只要0.74元的双通道数字隔离器,1T1R,增强型ESD-3.0 kV ,150Kbps数字隔离器

前言: 做和电源打交道的设备&#xff0c;通信时非常危险&#xff0c;一定要使用隔离的USB-232转换器&#xff0c;或者你设备的串口与市电直连的设备通信时&#xff0c;现在需要使用数字隔离器&#xff0c;早期的一般都使用光耦&#xff0c;在这种情况下&#xff0c;速度不搞的…

正则表达式:量词(三)

正则表达式中的量词有以下几种:1. *: 匹配前面的字符0次或多次。2. : 匹配前面的字符1次或多次。3.?: 匹配前面的字符0次或1次。4. {n}: 匹配前面的字符恰好n次。5. {n,}: 匹配前面的字符至少n次。6. {n,m}:匹配前面的字符至少n次&#xff0c;但不超过m次。 以下是使用Python的…

Unity TextMeshProUGUI 获取文本尺寸·大小

一般使用ContentSizeFitter组件自动变更大小 API 渲染前 Vector2 GetPreferredValues(string text)Vector2 GetPreferredValues(string text, float width, float height)Vector2 GetPreferredValues(float width, float height) 渲染后 Vector2 GetRenderedValues()Vector…

idea 卡怎么办

设置内存大小 清缓存重启 idea显示内存全用情况 右下角

解决CSS中鼠标移入到某个元素其子元素被遮挡的问题

我们在开发中经常遇到一种场景&#xff0c;就是给元素加提示信息&#xff0c;就是鼠标移入到盒子上面时&#xff0c;会出现提示信息这一功能&#xff0c;如果我们给盒子加了hover&#xff0c;当鼠标移入到盒子上时&#xff0c;让他往上移动5px&#xff0c;即transform: transla…

网盘——搜索用户

目录 1、搜索用户 1.1、在friend.h里面定义槽函数 1.2、关联槽函数 1.3、搜索用户的时候&#xff0c;会弹出一个对话框来,在friend.cpp里面引入下面的头文件&#xff0c;专门用来输入数据的 1.4、获取输入信息&#xff0c;并使用Qstring来接收它 1.5、将上述代码打包&…

AR地图导览小程序是怎么开发出来的?

在移动互联网时代&#xff0c;AR技术的发展为地图导览提供了全新的可能性。AR地图导览小程序结合了虚拟现实技术和地图导航功能&#xff0c;为用户提供了更加沉浸式、直观的导览体验。本文将从专业性和思考深度两个方面&#xff0c;探讨AR地图导览小程序的开发方案。 编辑搜图 …

时间复杂度详解2——时间复杂度的计算

时间复杂度基本计算规则&#xff1a; 基本操作即只有常数项&#xff0c;认为其时间复杂度为O(1)顺序结构&#xff0c;时间复杂度按加法进行计算循环结构&#xff0c;时间复杂度按乘法进行计算分支结构&#xff0c;时间复杂度取最大值判断一个算法效率时&#xff0c;往往只需要…

HubSpot如何通过自动化和优化客户服务流程?

在当今竞争激烈的市场环境中&#xff0c;提供卓越的客户服务体验已经成为企业赢得客户忠诚、推动业务增长的关键所在。HubSpot&#xff0c;作为一款领先的客户关系管理软件&#xff0c;通过自动化和优化客户服务流程&#xff0c;为企业带来了革命性的服务体验提升。 HubSpot通…

对LSTM的通俗易懂理解--可变权重

RNN的问题&#xff1a;长期依赖&#xff0c;即对短期的数据敏感&#xff0c;对比较远的长期数据不敏感&#xff0c;这是因为RNN隐藏状态权重在不同时刻是共享相同的&#xff0c;随着时间步的增加&#xff0c;梯度会指数级地衰减或者增长&#xff0c;导致梯度消失或者爆炸&#…

稀碎从零算法笔记Day47-LeetCode:找到冠军 I

或许是昨天的每日一题太难了&#xff0c;今天的简单 题型&#xff1a;数组、矩阵 链接&#xff1a;2923. 找到冠军 I - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 一场比赛中共有 n 支队伍&#xff0c;按从 0 到 n - 1 编号。 给你一个下…

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第三套

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第三套 (共9套&#xff0c;有答案和解析&#xff0c;答案非官方&#xff0c;未仔细校正&#xff0c;仅供参考&#xff09; 部分题目分享&#xff0c;完整版获取&#xff08;WX:didadidadidida313&#xff0c;加我备注&#x…