自己实现C++的string类
使用C++的朋友对string类都不会陌生,string类使用起来很是方便,比C的字符数组好用多了,但是我们能不能自己实现一个属于自己的string类呢?
实现一个具有基本功能的string类并不难,但是还是得掌握以下几点知识:构造函数、析构函数、运算符重载、指针、引用等等。
我自己实现了一个string类,一来是想用自己学的知识做一些有实际作用的东西,二则使用自己的东西也很有成就感,现在给大家作为参考,有错误或者不合理的地方欢迎大家指正。
为了区别标准库中的string类和相关标识符,我的类名叫mystring,而相关函数名也大多以这种方式处理,其中每个函数都经过本人测试,在参数合法的前提下均能正常使用,但组合在一起使用的情况则没有进行太多测试。
首先是mystring.h文件
#ifndef MYSTRING_H_INCLUDED
#define MYSTRING_H_INCLUDED #include <iostream> using namespace std; class mystring
{
public:
mystring();
mystring(const char * ptr_s);
mystring(const mystring & refer_str);//拷贝构造函数
int mylength();//计算字符串的长度
~mystring();
friend istream & operator>>(istream & is, mystring & refer_str);
friend ostream & operator<<(ostream & os, const mystring & refer_str);
mystring & operator=(const mystring & refer_str);
void mygetline();//对输入按行读取
char & operator[](int n);
friend mystring operator+(const mystring & refer_str_1, const mystring & refer_str_2);
mystring & operator+=(const mystring & refer_str);
friend bool operator==(const mystring & refer_str_1, const mystring & refer_str_2);
friend bool operator!=(const mystring & refer_str_1, const mystring & refer_str_2);
mystring mysubstr(int pos, int posn);//计算一个字符串的子串,pos为起始位置,从0开始,posn为希望求得的子串的长度
friend void mystrswap(mystring & str1, mystring & str2);//交换两个字符串
int myfind(char ch, int pos = );//从pos开始查找字符ch在当前字符串中的位置,pos从0开始,返回值也从0开始
mystring & myerase(int pos, int posn);//从pos开始删除当前字符串中的字符,pos从0开始,posn表示希望删除的字符数量,返回删除后字符串的引用,也即当前字符串
mystring & myinsert(int pos, const mystring & refer_str);//将refer_str代表的字符串插入到当前字符串中,pos表示插入的位置,0 <= pos <= mystrlen((*this).ptr_s)
mystring & myinsert(int pos, const mystring & refer_str, int posn);//将refer_str代表的字符串插入到当前字符串中,pos表示插入的位置,0 <= pos <= mystrlen((*this).ptr_s),0 <= posn <= mystrlen(refer_str.ptr_s)
private:
char * ptr_s;
}; int mystrlen(const char * ptr_s);//计算字符串的长度
void mystrcpy(char * ptr_s_1, const char * ptr_s_2);//将ptr_s_2指向的内容复制到ptr_s_1所指向的空间,但前提后者空间足够
int mystrcmp(const char * ptr_s_1, const char * ptr_s_2);//比较ptr_s_1指向的内容和ptr_s_2指向的内容,若两者相同返回0,前者大返回1,前者小返回-1
void mystrcat(char * ptr_s_1, const char * ptr_s_2);//将ptr_s_2指向的内容连接到ptr_s_1指向的内容的后面,但需保证ptr_s_1所指向的空间足够,并且ptr_s_1所指向的空间必须经过初始化,即包含有意义的字符串结束符\0 #endif // MYSTRING_H_INCLUDED
我的想法是尽量不使用标准库,但为了重载>>和<<这两个运算符并实现mygetline()函数,还是得在mystring.h中包含iostream。
然后是mystring.cpp文件
#include "mystring.h" mystring::mystring()
{
ptr_s = new char[];
*ptr_s = '\0';
} mystring::mystring(const char * ptr_s)
{
this->ptr_s = new char[mystrlen(ptr_s)+];
mystrcpy(this->ptr_s, ptr_s);
} mystring::mystring(const mystring & refer_str)
{
ptr_s = new char[mystrlen(refer_str.ptr_s)+];
mystrcpy(ptr_s, refer_str.ptr_s);
} int mystring::mylength()
{
return mystrlen(ptr_s);
} mystring::~mystring()
{
delete [] ptr_s;
} istream & operator>>(istream & is, mystring & refer_str)
{
delete [] refer_str.ptr_s;
char ch_tmp[];// 申请一块在一般情况下足够大的内存
is >> ch_tmp;
refer_str.ptr_s = new char[mystrlen(ch_tmp)+];
mystrcpy(refer_str.ptr_s, ch_tmp);
return is;
} ostream & operator<<(ostream & os, const mystring & refer_str)
{
os << refer_str.ptr_s;
return os;
} mystring & mystring::operator=(const mystring & refer_str)
{
if(this == &refer_str)
return *this;
else
{
delete [] ptr_s;
ptr_s = new char[mystrlen(refer_str.ptr_s)+];
mystrcpy(ptr_s, refer_str.ptr_s);
return *this;
}
} void mystring::mygetline()
{
delete [] ptr_s;
char ch_tmp[];// 申请一块在一般情况下足够大的内存
cin.getline(ch_tmp, );
ptr_s = new char[mystrlen(ch_tmp)+];
mystrcpy(ptr_s, ch_tmp);
} char & mystring::operator[](int n)
{
return *(ptr_s+n);
} mystring operator+(const mystring & refer_str_1, const mystring & refer_str_2)
{
mystring str_tmp;
str_tmp.ptr_s = new char[mystrlen(refer_str_1.ptr_s)+mystrlen(refer_str_2.ptr_s)+];
mystrcpy(str_tmp.ptr_s, refer_str_1.ptr_s);
mystrcpy(str_tmp.ptr_s+mystrlen(refer_str_1.ptr_s), refer_str_2.ptr_s);
return str_tmp;
} mystring & mystring::operator+=(const mystring & refer_str)
{
mystring str_tmp;
str_tmp.ptr_s = new char[mystrlen(ptr_s)+mystrlen(refer_str.ptr_s)+];
mystrcpy(str_tmp.ptr_s, ptr_s);
mystrcpy(str_tmp.ptr_s+mystrlen(ptr_s), refer_str.ptr_s);
delete [] ptr_s;
ptr_s = new char[mystrlen(str_tmp.ptr_s)+];
mystrcpy(ptr_s, str_tmp.ptr_s);
return *this;
} bool operator==(const mystring & refer_str_1, const mystring & refer_str_2)
{
int ret = mystrcmp(refer_str_1.ptr_s, refer_str_2.ptr_s);
if(ret == )
return true;
else
return false;
} bool operator!=(const mystring & refer_str_1, const mystring & refer_str_2)
{
int ret = mystrcmp(refer_str_1.ptr_s, refer_str_2.ptr_s);
if(ret == )
return false;
else
return true;
} mystring mystring::mysubstr(int pos, int posn)
{
mystring str_tmp;
delete [] str_tmp.ptr_s;
str_tmp.ptr_s = new char[posn+];
for(int i = ;i < posn;i++)
*(str_tmp.ptr_s+i) = *(ptr_s+pos+i);
*(str_tmp.ptr_s+posn) = '\0';
return str_tmp;
} void mystrswap(mystring & str1, mystring & str2)
{
char * ptr_s;
ptr_s = str1.ptr_s;
str1.ptr_s = str2.ptr_s;
str2.ptr_s = ptr_s;
} int mystring::myfind(char ch, int pos)
{
int str_length = mystrlen(ptr_s);
int i;
for(i = ;i < str_length-pos;i++)
if(*(ptr_s+pos+i) == ch)
return pos+i;
return -;
} mystring & mystring::myerase(int pos, int posn)
{
mystring str_tmp;
delete [] str_tmp.ptr_s;
int str_length = mystrlen(ptr_s);
str_tmp.ptr_s = new char[str_length-posn+];
for(int i = ;i < pos;i++)
*(str_tmp.ptr_s+i) = *(ptr_s+i);
for(int i = pos+posn;i < str_length;i++)
*(str_tmp.ptr_s+i-posn) = *(ptr_s+i);
*(str_tmp.ptr_s+str_length-posn) = '\0';
char * ptr_s_tmp;
ptr_s_tmp = str_tmp.ptr_s;
str_tmp.ptr_s = ptr_s;
ptr_s = ptr_s_tmp;
return *this;
} mystring & mystring::myinsert(int pos, const mystring & refer_str)
{
mystring str_tmp;
delete [] str_tmp.ptr_s;
int str_length_1 = mystrlen(ptr_s);
int str_length_2 = mystrlen(refer_str.ptr_s);
str_tmp.ptr_s = new char[str_length_1+str_length_2+];
int i;
for(i = ;i < pos;i++)
*(str_tmp.ptr_s+i) = *(ptr_s+i);
mystrcpy(str_tmp.ptr_s+i, refer_str.ptr_s);
while(i < str_length_1)
{
*(str_tmp.ptr_s+str_length_2+i) = *(ptr_s+i);
i++;
}
*(str_tmp.ptr_s+str_length_1+str_length_2) = '\0';
char * ptr_s_tmp;
ptr_s_tmp = str_tmp.ptr_s;
str_tmp.ptr_s = ptr_s;
ptr_s = ptr_s_tmp;
return *this;
} mystring & mystring::myinsert(int pos, const mystring & refer_str, int posn)
{
mystring str_tmp;
delete [] str_tmp.ptr_s;
int str_length = mystrlen(ptr_s);
str_tmp.ptr_s = new char[str_length+posn+];
int i;
for(i = ;i < pos;i++)
*(str_tmp.ptr_s+i) = *(ptr_s+i);
for(int j = ;j < posn;j++)
*(str_tmp.ptr_s+pos+j) = *(refer_str.ptr_s+j);
while(i < str_length)
{
*(str_tmp.ptr_s+posn+i) = *(ptr_s+i);
i++;
}
*(str_tmp.ptr_s+str_length+posn) = '\0';
char * ptr_s_tmp;
ptr_s_tmp = str_tmp.ptr_s;
str_tmp.ptr_s = ptr_s;
ptr_s = ptr_s_tmp;
return *this;
} int mystrlen(const char * ptr_s)
{
int length = ;
while(*(ptr_s++) != '\0')
length++;
return length;
} void mystrcpy(char * ptr_s_1, const char * ptr_s_2)
{
while(*ptr_s_2 != '\0')
{
*ptr_s_1 = *ptr_s_2;
ptr_s_1++;
ptr_s_2++;
}
*ptr_s_1 = '\0';
} int mystrcmp(const char * ptr_s_1, const char * ptr_s_2)
{
int length_1 = mystrlen(ptr_s_1);
int length_2 = mystrlen(ptr_s_2);
int length_shorter = length_1 > length_2 ? length_2 : length_1;
int i;
for(i = ;i < length_shorter;i++)
if(*(ptr_s_1+i) != *(ptr_s_2+i))
break;
if(i == length_shorter)
{
if(length_1 == length_2)
return ;
else if(length_1 > length_2)
return ;
else
return -;
}
else
{
if(*(ptr_s_1+i) > *(ptr_s_2+i))
return ;
else
return -;
}
} void mystrcat(char * ptr_s_1, const char * ptr_s_2)
{
ptr_s_1 += mystrlen(ptr_s_1);
while(*ptr_s_2 != '\0')
{
*ptr_s_1 = *ptr_s_2;
ptr_s_1++;
ptr_s_2++;
}
*ptr_s_1 = '\0';
}
实现时很多地方用到了指针,指针确实非常强大。
这样只要将这两个文件放在目标工程文件夹里,并且在开头加上
#include "mystring.h"
就可以使用自己的string类了,如果自己需要什么个性化的功能,还可以自由添加修改。
2017年8月9日15:52:02更新
发现巨大漏洞,我在new之后没有对相应指针进行检查,可能出现在没有成功分配内存的情况下使用内存,有可能导致程序崩溃。犯了一个新手错误,但是我还不知道如果内存分配失败应该做什么。
2017年8月9日18:25:39更新
刚刚知道new在分配内存失败后默认抛出异常,而不是把指针赋值为NULL,故应该用try-catch语句进行检查。
自己实现C++的string类的更多相关文章
- 标准库String类
下面的程序并没有把String类的所有成员方法实现,只参考教程写了大部分重要的成员函数. [cpp] view plain copy #include<iostream> #include ...
- 自己实现简单的string类
1.前言 最近看了下<C++Primer>,觉得受益匪浅.不过纸上得来终觉浅,觉知此事须躬行.今天看了类类型,书中简单实现了String类,自己以前也学过C++,不过说来惭愧,以前都是用C ...
- C++ string类的实现
c++中string类的实现 今天面试被考到了, 全给忘记了!!! //string类的实现 #include <iostream> #include <string.h> ...
- String类的功能
String类 标红的为较少出现的 1.判断功能 boolean equals(Object obj) :比较字符串内容是否相同,区分大小写 boolean equalsIg ...
- java基础复习:final,static,以及String类
2.final 1)为啥String是final修饰的呢? 自己答: 答案: 主要是为了“效率” 和 “安全性” 的缘故.若 String允许被继承, 由于它的高度被使用率, 可能会降低程序的性能,所 ...
- String类和StringBuffer类的区别
首先,String和StringBuffer主要有2个区别: (1)String类对象为不可变对象,一旦你修改了String对象的值,隐性重新创建了一个新的对象,释放原String对象,StringB ...
- 05_整理String类的Length()、charAt()、 getChars()、replace()、 toUpperCase()、 toLowerCase()、trim()、toCharArray()使用说明
Question: 整理String类的Length().charAt(). getChars().replace(). toUpperCase(). toLowerCase().trim().toC ...
- 标准C++中的string类的用法总结
标准C++中的string类的用法总结 相信使用过MFC编程的朋友对CString这个类的印象应该非常深刻吧?的确,MFC中的CString类使用起来真的非常的方便好用.但是如果离开了MFC框架,还有 ...
- String类常用方法
1.String类的特点,字符串一旦被初始化就不会被改变. 2.String对象定义的两种方式 ①String s = "affdf";这种定义方式是在字符串常量池中创建一个Str ...
- 运用String类实现一个模拟用户登录程序
package Test; import java.util.Scanner; // 模拟用户登录程序 // 思路: // 1.用两个String类分别接收用户名和密码 // 2.判断输入的用户名和密 ...
随机推荐
- vs2015+opencv3.3.1 实现 c++ 彩色高斯滤波器(Gaussian Smoothing, Gaussian Blur, Gaussian Filter)
//高斯滤波器 https://github.com/scutlzk#include <opencv2\highgui\highgui.hpp> #include <iostream ...
- linux 改变系统时间
date 查看系统时间 date -s 04/05/16 日期设置成2016年4月5日 date -s 15:03:32 日期设置成2016年4月5日15:03:32 上述两步可以直接写成这样一 ...
- springboot项目部署运行(后台);端口被占用;
打包: mvn clean package -Pprod -Dmaven.test.skip=true -Pprod 使用生产环境配置: -DskipTests,不执行测试用例,但编译测试用例类生成相 ...
- linux上使用tomcat及查看日志
启动 startup.sh #执行bin/startup.sh #启动tomcatbin/shutdown.sh #停止tomcattail -f logs/catalina.out #看tomcat ...
- Django之跨域请求同源策略
同源策略: 首先基于安全的原因,浏览器是存在同源策略这个机制的,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性. 而如果我们要跳过这个策略,也就是说非要跨域请求,那么就需要通过 ...
- 洛谷P4207 [NOI2005]月下柠檬树(计算几何+自适应Simpson法)
题面 传送门 题解 我还好奇自适应辛普森法干嘛用的呢--突然想起来积分的一个用处就是求曲边图形的面积-- 我们先来考虑一下这些投影是什么形状 一个圆的投影还是它自己 一个圆锥的投影是一个圆加上一个点, ...
- linux防火墙(二)—— iptables语法之选项和控制类型
一.语法: iptables [-t 表名] 选项 [链名] [匹配条件] [-j 控制类型] 未指定表名时,默认用filter表:链名,控制类型要大写:除非设置默认策略,否则必须指定匹配条件:不指定 ...
- Python描述符深入理解
Python的描述符乍眼看去简单,但是细节方面如果不注意容易掉坑,总结以下几个坑,以作备忘,先看代码: class D: def __get__(self, inst, owner): if inst ...
- 使用过多的递归出现错误,“System.StackOverflowException”类型的未经处理的异常在 mscorlib.dll 中发生
class Program { static void Main(string[] args) { sub(0); } private static void sub(int count) { ...
- Qt 学习之路 2(47):视图选择
Qt 学习之路 2(47):视图选择 豆子 2013年3月28日 Qt 学习之路 2 34条评论 选择是视图中常用的一个操作.在列表.树或者表格中,通过鼠标点击可以选中某一项,被选中项会变成高亮或者反 ...