字符串String类的完整实现 C++程序设计语言第11章

C++string类 🔥在C++中,迭代器(lterator)是用于访问和遍历容器(如vector、list、map等)元素的核心工具,其本质是一个类似指针的对象,但提供了更统一的抽象接口,能够屏蔽不同容器的底层实现细节。(1) 迭代器的核心特性1.功能定义迭代器通过指针式的操作(如递增、解引用等)访问容器元素,通常支持以下基本操作:● 指向容器中的元素(类似指针)。● 通过++或 – 移动位置(支持单向或双向移动,取决于迭代器类型● 通过*操作符访问或修改元素值。2.核心作用。 阅读详情

这是一个很有趣的练习。它让我了解了标准库String类的实现,并且增强了我对面向对象编程的理解。这个String类的对象基于采用引用计数的String类表示(Srep),多个String之间将会共享同一个表示。并且在写时仍然采用值语义(即,对一个String的操作不会影响到另一个String),这使用了一种叫“写时复制”的计数,只在对String类进行修改时再复制String类对象。这个良好的策略将会使得用户即可以使用值语义的String字符串又可以不用负担过大的内存开销(因为保存同一内容的String会共享同一表示)。

还有一个很关键的部分是Cref这个成员类。这个类的作用相当于一个char&,在调用String的下标操作符时返回。然而,为什么不直接返回一个char&呢?因为如果直接返回char&的话就允许了用户对String的随意修改,而这与String的设计意图是矛盾的。String的设计意图是在修改String时对String进行复制(与原来共享的表示分离)。也就是说,我们并不想返回一个低级表示给用户随意使用。在这种情况下我们定义了一个Cref类。这个类将在用户读取String的[]下标内容时转换为一个char,而在用户修改这个字符(例如,String[0]='a')时复制String的表示(通过定义赋值操作符)。

这些练习中最困难的是设计String类使得子串可以用在赋值的左边。我仔细想了想这里也应该运用相同的策略:返回一个Sref类型保存绑定到String的子串的引用。在读取时返回一个String,在修改时对原String进行复制。

我还定义了一个find(const String&)函数。注意到我在find函数中并没有进行逐个的char比较,而是调用了operator==比较参数和目标String的子串。这也是C++程序设计语言一直强调的,尽量少操作对象的直接表示。

输入操作符operator>>我的实现很简陋,创建一个大小为20的char数组保存输入。我无法想出一个更好的实现。如果大家有更好的实现方法,希望能留言建议,谢谢!

String.h

//2.(*2) 完成并测试String类。(完成拼接运算符和IO操作符) 
//7.(*2) 为String 类定义一个外部迭代器String_tier。添加一些操作。 
//8.(*1.5) 通过重载()为String类提供一个字串操作。
//9.(×3) 设计String类使得字串可以用在赋值的左边。
//写一个版本允许给串赋的字串长度变化。 
//10.(*2) 为String定义一个操作,产生其值的C字串表示。 
//11.(*2.5) 为String定义和实现一个简单的模式匹配功能函数。
//(我实现的是一个find函数。) 

#ifndef STRING_H
#define STRING_H

#include <iostream>
#include <cstring>
class String{
	struct Srep{
    	char* s;
    	int sz;
    	int n;
        
        Srep(int nsz,const char* p):
            sz(nsz),n(1),s(new char[sz+1]){strcpy(s,p);}
        ~Srep(){delete[] s;}
        
        Srep* get_own_copy()
    	{
    		if(n==1) return this;
    		--n;
    		return new Srep(sz,s);
    	}
    	void assign(int nsz,const char* p)
    	{
    		if(sz!=nsz){
    			delete[] s;
    			sz=nsz;
    			s=new char[sz+1];
    		}
    		strcpy(s,p);
        }
    private:
        Srep(const Srep&);
        Srep& operator=(const Srep&);
    };
    Srep* rep;
public:
    friend class String_iter;

    class Cref{
    	friend class String;
	    String& s;
	    int i;
	    Cref(String& ss,int ii):s(ss),i(ii){}
    public:
        operator char() const{return s.read(i);}
        void operator=(char c){s.write(i,c);}
    };
    class Sref{
        friend class String;
        String& s;
        int nbeg,nend;
        Sref(String& ss,int b,int e):s(ss),nbeg(b),nend(e){}
    public:
        operator String() const
		    {return static_cast<const String&>(s)(nbeg,nend);}
        void operator=(const String& ss)
        {
        	if(nend-nbeg==ss.size()-1){
              	s.rep=s.rep->get_own_copy();
            	for(int ix=nbeg;ix<=nend;++ix)
            	    s.rep->s[ix]=ss.rep->s[ix];
            }else{
            	//这里的方法未必要一样。只要可行即可。 :
            	String left=
				    nbeg==0?"":static_cast<const String&>(s)(0,nbeg-1);
            	String right=
				    nend==s.rep->sz-1?"":static_cast<const String&>(s)(nend+1,s.rep->sz-1);
            	s=String();
				((const_cast<String&>(s)+=left)+=ss)+=right;
            }
        }
    };
    class Range{};
    
    String():rep(new Srep(0,"")){}
    String(const char* s):rep(new Srep(strlen(s),s)){}
    String(const String& x)
    {
    	++x.rep->n;
    	rep=x.rep;
    }
    String& operator=(const char*);
    String& operator=(const String&);
    
    String& operator+=(const char* s)
	{
	    rep=rep->get_own_copy();
		strcat(rep->s,s);
		rep->sz+=strlen(s);
		return *this;
	}
    String& operator+=(const String& x)
	{
	    rep=rep->get_own_copy();
		strcat(rep->s,x.rep->s);
		rep->sz+=x.rep->sz;
		return *this;
	}
    
    friend std::ostream& operator<<(std::ostream& os,const String& x)
        {return os<<x.rep->s;}
    friend std::istream& operator>>(std::istream&,String&);
    
    friend bool operator==(const String& x,const char* s)
        {return strcmp(x.rep->s,s)==0;}
    friend bool operator==(const String& x,const String& y)
        {return strcmp(x.rep->s,y.rep->s)==0;}
    friend bool operator!=(const String& x,const char* s)
        {return strcmp(x.rep->s,s)!=0;}
    friend bool operator!=(const String& x,const String& y)
        {return strcmp(x.rep->s,y.rep->s)!=0;}
    
    ~String(){if(--rep->n==0) delete rep;}
    
    void check(int i) const{if(i<0||rep->sz<=i) throw Range();}
    char read(int i) const{return rep->s[i];}
    void write(int i,char c){rep=rep->get_own_copy();rep->s[i]=c;}
    
    int find(const String&) const;
    
    char operator[](int i) const{check(i);return rep->s[i];}
    Cref operator[](int i){check(i);return Cref(*this,i);}
    
    String operator()(int,int) const;
    Sref operator()(int,int);

    const char* c_str() const{return rep->s;}
    int size() const{return rep->sz;}
};
String& String::operator=(const char* s)
{
	if(rep->n==1)
	    rep->assign(strlen(s),s);
    else{
    	--rep->n;
        rep=new Srep(strlen(s),s);
    }
    return *this;
}
String& String::operator=(const String& x)
{
	++x.rep->n;
	if(--rep->n==0) delete rep;
    rep=x.rep;
    return *this;
}
String String::operator()(int nbeg,int nend) const
{
	check(nbeg);check(nend);
	if(nbeg<=nend){
        char *ca=new char[nend-nbeg+2];
        strncpy(ca,rep->s+nbeg,nend-nbeg+1);
        ca[nend-nbeg+1]='\0';
        String ret(ca);
        delete[] ca;
        return ret;
	}else
	    return String("");
}
String::Sref String::operator()(int nbeg,int nend)
{
	check(nbeg);check(nend);
	if(nbeg<=nend){
		return Sref(*this,nbeg,nend);
	}else{
		String tp("");
		String& temp=tp;
	    return Sref(temp,0,0);
	}
}
int String::find(const String& x) const
{
	int pos=0;
	int sz=x.size();
	while(pos+sz<=this->size()&&x!=this->operator()(pos,pos+sz-1))
	    ++pos;
    if(pos+sz<=this->size())
        return pos;
    else
        return -1;
}
String operator+(const String& x,const char* s)
{
	String ret(x);
	ret+=s;
	return ret;
}
String operator+(const String& x,const String& y)
{
	String ret(x);
	ret+=y;
	return ret;
}
std::istream& operator>>(std::istream& is,String& x)
{
	char* s=new char[20];
	is>>s;
	x=s;
	return is;
}
class String_iter{
	mutable int ix;
	String& str;
public:
    String_iter(String& s):str(s),ix(0){}
    char& next()
	{
		str.rep=str.rep->get_own_copy();
	    return str.rep->s[ix++];
	}
    char next() const{return str.rep->s[ix++];}
    
    String_iter& operator++(){++ix;return *this;}
    String_iter operator++(int);
    
    String_iter& operator--(){--ix;return *this;}
    String_iter operator--(int);
};
String_iter String_iter::operator++(int)
{
	String_iter ret(*this);
	++*this;
	return ret;
}
String_iter String_iter::operator--(int)
{
	String_iter ret(*this);
	++*this;
	return ret;
}

#endif

main.cpp

#include <iostream>
#include "String.h"
using namespace std;
int main()
{
	String s("Hello C++");
	cout<<s<<endl;
	cout<<s.find("C++")<<endl;
	s(6,8)="World";
	cout<<s<<endl;
	cout<<s(0,4)<<endl;
	return 0;
}

大家有什么不懂的可以问。乐意解答。

C++程序设计关于字符串的基本操作 期末课程设计题目,使用C++实现关于字符串的基本操作,本人也是学生,初学,写的不好,仅供参考。 立即下载

相关推荐

String类的完整实现包括

*String类中包括以下函数:* *默认构造函数,带参数构造函数 , 拷贝构造函数 *取字符串函数GetString(),取字符串长度函数GetLength(),查找字串位置函数Find() *重载<>,[],=,+,> *析构函数 *String类中包括2个数据成员:* *字符串首地址m_string *字符串长度m_size

C++STL详解(二)—— string类的模拟实现

文章目录

2021dragon的博客 5599

一个完整C++ 类实现简单代码

一个完整描述类实现的代码,语句有具体描述,适合初学者加深对类的认知,包含构造函数和析构函数的实现,代码是在VS2010环境下编写。

【C++ 十一】C++ string容器

本文包含string基本概念、string构造函数、string赋值操作、string字符串拼接、string查找和替换、string字符串比较、string字符串存取、string插入和删除、string子串。

qq_45138120的博客 1638

OCSP环境搭建--Windows Server 2016

OCSP环境搭建--Windows Server 2016 一. OCSP环境中相关信息 1. 服务器1 操作系统:Win Server 2016 Standard版 IP地址:172.16.0.19/23,网关:172.16.0.1,首选DNS:127.0.0.1 服务器角色:域控制器、证书颁发机构、radius服务器、DNS服务器 ...

CsdnCHong_566的博客 3352

GenomeSurvyIndex设计--随笔017

摘要: GenomeSurvyIndex是一款自动化多倍体基因组调查工具,整合FastK、Smudgeplot和GenomeScope2.0三大核心组件。该工具通过k-mer频谱特征自动识别基因组倍性类型,包括二倍体(1:2:4)和同源四倍体(1:2:3:4),并采用3a1b>2a2b算法判定同源/异源多倍体。工具提供完整的conda环境配置方案,封装为Python脚本实现全流程自动化分析,包含k-mer计数、倍性判定、基因组特征计算等功能,最终输出标准化报告和可视化图表。该方案可直接部署使用,适用于

weixin_44874487的博客 475

类的实现(c++)

类的完整实现(超级简洁,好上手教程)

qq_61561417的博客 2464

从Multibit到Debanking:芯片设计中的时序优化完整流程解析(含真实案例)

本文深入解析芯片设计中Multibit技术与Debanking的时序优化完整流程,结合7nm移动SoC真实案例,详细探讨Multibit的核心优势、实施条件及潜在风险,并提供Debanking的触发时机与操作策略。通过平衡Multibit与Debanking,工程师可有效优化PPA(Power-Performance-Area),提升芯片设计效率。

weixin_30316097的博客 460

C++(11)——string

文章将对上述图片中某几个常用的函数进行介绍,其他函数的使用方法可以通过上方网址进行查阅。对于二者的不同点,可以认为第一种可读可写,但是第二种只能读。,是用于反应这个对象中字符串的长度的。进行扩容时,扩容后的大小并不一定等于预设的值,通常会大于这个值。的大小只和该类型能够存储多少内容有关,与对象中是否有内容无关。只能改变空间,并不能影响对象中的内容。类对象进行缩容时,并不能缩小到这个对象的最小容量。上面说到,对于第一种方式,不光可读,而且可写,因此,让。进行扩容后,发现,此时扩充的部分的值全部为。

2301_76836325的博客 1132

软件测试面试题汇总

软件测试面试题汇总 测试技术面试题 ........................................................................................................................................................................ 5 1、什么是兼容

晴天的专栏 2万+

05 SAP CPI 访问第一个CPI接口

其中的clientid的值可作为Basic验证的用户名,clientsecret的值可作为Basic验证的密码。点击SEND按钮,可看见返回状态为200 OK。在04中,我们得到TOKEN令牌。POSTMAN向下滚动。点击按钮获取token。

SAP CPI 663

Learning C++ No.11【string类实现】

string类实现

狂小伍的博客 1402

unity6000.0.3版本URP下ScriptableRendererFeature如何实现一张自定义贴图效果?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值。

**My Coding Family** 585

【C++】string类

C++ string类解析摘要 本文全面解析C++ string类,重点包括: string类解决了C语言字符串的4大痛点:安全性问题、内存管理复杂、功能有限、不符合面向对象思想 string类基础用法和C++11新特性(auto关键字和范围for循环) 详细介绍了5类核心接口: 构造函数(空字符串、C字符串构造等) 容量操作(size()/length()、resize()等) 元素访问和遍历(下标操作、迭代器、范围for) 通过代码示例演示string类的实际应用,包括字符串处理和安全操作 string

凤年徐的博客 3477

Android 11多窗口+分屏+APP窗口嵌套TaskView实现原理一

然而随着版本的迭代升级,google对分屏的定制差异化也越来越大,Androd 11的分屏用的是split-screen-primary和split-screen-secondary的方式,在systemui中去实现的,其定制化的灵活度不是很高,很多业务都是放到sustemui或者fw去实现,但是随着版本的升高,后面出现了TaskView来替代了老版本的分屏方式,但是Task的核心原理其实和之前的方式是一样的,TaskView来实现分屏。

qq_18420641的博客 2615

某易将军令口令纯算法还原py篇

算法开源,将军令口令算法。希望官方多多更新吧

任雪飘的博客 3909

C++【string类,模拟实现string类】

就像一个家庭中有两个孩子,但父母只买了一份玩具,两个孩子愿意一块玩,则万事大吉,万一 不想分享就你争我夺,玩具损坏。可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享。父 母给每个孩子都买一份玩具,各自玩各自的就不会有问题了。

qq_67578580的博客 3697

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C++string类常用方法

C++string类常用方法 1、string(const char *s) :将 string 对象初始化为 s 指向的字符串 string str("hello"); 2、string(size_type n,char c) :创建一个包含 n 个元素的 string 对象,其中每个元素都被初始化为字符 c string str(10, 'a'); 3、string(const string &str) :将一个 string 对象初始化为 string 对象 str(复制构造函数) str

Goallegoal的博客 9万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

C++编程语言中string类介绍

string类是C++标准库的一个重要的部分,主要用于字符串处理。可以使用输入输出流方式直接进行string操作,也可以通过文件等手段进行string操作。同时,C++的算法库对string类也有着很好的支持,并且string类还和C语言的字符串之间有着良好的接口。

liitdar的博客 31万+

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

【C++STL】告别 C 字符串噩梦!C++ string 类从入门到精通,含实战避坑指南

本文从 STL 框架出发,先说明 C 字符串存在数据与操作分离、内存需手动管理、易越界等问题,凸显 C++ string 类的优势。接着介绍 C++11 的 auto(简化类型声明)和范围 for(便捷遍历)语法。再梳理 string 核心接口,包括构造、容量(如大小、预留空间)、访问(如数组式访问)、修改(如拼接、查找)等功能用法。深入解析 VS 的 “小字符串优化” 与 G++ 的 “写时拷贝” 两种底层实现差异,重点讲浅拷贝的致命问题及传统、现代两种深拷贝实现方法,文末附 string 模拟实现资源

2402_87731470的博客 3557

【C++】——string类的使用

引入size() 的原因是为了与其他容器的接。

2402_82668782的博客 2162

c++ primer plus 第16章string 类和标准模板库,string 类

c++ primer plus 第16章string 类和标准模板库,string 类。

zhyjhacker的博客 1390

【C++指南】告别C字符串陷阱:如何实现封装string?

本章节剖析string中常用接口:构造、容量操作、迭代器、修改、非成员函数,模拟stl库中函数实现对应接口,并引入了两个C++11引入的新语法auto和范围for。

egoist2023的博客 3268

【c++丨STL】string类的使用

今天,我们正式进入了STL的大门,学习了第一个容器——string。string虽然接口较多,但是它的实用性很高,为我们处理字符串提供了很多便利。由于其中一些接口并不是很常用,博主就没有过多赘述,大家可以在cplusplus官网进一步了解它们。之后博主会和大家一起,在熟练运用的基础上,深入其底层,并尝试模拟实现string类。

2301_80955819的博客 1812

【C++】自主实现string类

因为end是int类型的,pos是size_t的,不同类型比较时要先转换成同种类型,所以将int转换成size_t,因为size_t是无符号整型unsigned int,它>=0,因此将end转换成size_t类型的临时变量与pos==0相比较,永久成立,因此会死循环(end会变成负数,但是将end转换成size_t类型的临时变量,该临时变量是>=0的)要求:当n<=_size时,string类对象的内容变为_str[0,n],_str[n]=’\0’,即有效的字符个数变为n,不缩容。

qq_75000174的博客 1904

【C++语言】string 类

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

加油,考上985的研究生 822
上一篇: C++ 计算器Calculator类实现
下一篇: 基于Vector实现的Map类 《C++程序设计语言》第13章
laochen46
博客等级 码龄18年 13粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值