C++之自己实现的String类全部
一:回顾
(1)c++中的string类是在面试中和笔试中经常考的题目; 工程代码免费下载 string类的自行实现
(2)c++中的string类和fstream类合起来是处理外部数据的利器;
(3)string类经常用到find find_first_of find_first_not_of find_last_of find_last_not_of substr replace等,以及联合使用来达到java中的split和trim
(4) 使用friend 仅仅是在类中进行声明的非内部 却可以访问内部成员的外部函数,而且在外部不再需要friend关键字;它与成员函数的区别是,friend和外部函数不含有this对象指针;本文用到了const 定义的全局最大值最小值变量(代替#define)
(5) 有些函数返回的是MyString& 、Char& 等(引用),MyString、Char 等(传值)这得看你返回的对象是函数的局部变量还是全局变量(或者类当前对象成员变量);前者只能返回一个MyString、Char 等;后者强烈建议返回MyString& 、Char& 等(引用);
(6)有些函数的参数是const MyString& ,有些是MyString& (引用);这是为什么?前者是把外部值传提到子函数内部,且不允许改变;后者是作为函数的返回值传递进去的,返回的结果为函数的处理结果(而不用函数自身返回值了)。
二:下面是简单的实现了一下string类,参照的是STL源码
头文件:
#ifndef MYSTRING_H
#define MYSTRING_H
#include "MyExcept.h"
#include <cstring>
#include <iostream>
const int INI_MAX = 0x7fffffff;//2^32npos
const int INI_MIN = 0x80000000;// -2^32
const int npos = 0xffffffff;// npos
using namespace std; class MyString
{
public:
// constructor
MyString();//
MyString(const MyString &);//
MyString(const char *);
MyString(const size_t,const char);
// destructor
~MyString();
// attributes size_t length();// 字符串长度
bool isEmpty();// 返回字符串是否为空
const char* c_str();// 返回c风格的trr的指针
// friend funs
// read writer operations
friend ostream& operator<< (ostream&, const MyString&);
friend istream& operator>> (istream&, MyString&);
//add operation
friend MyString operator+(const MyString&,const MyString&);
// compare operations
friend bool operator==(const MyString&,const MyString&);
friend bool operator!=(const MyString&,const MyString&);
friend bool operator<(const MyString&,const MyString&);
friend bool operator<=(const MyString&,const MyString&);
friend bool operator>(const MyString&,const MyString&);
friend bool operator>=(const MyString&,const MyString&);
// 成员函数实现运算符重载,其实一般需要返回自身对象的,成员函数运算符重载会好一些
// index operation
char& operator[](const size_t);
const char& operator[](const size_t)const;
// =
MyString& operator=(const MyString&);
// +=
MyString& operator+=(const MyString&);
// +=
//MyString operator+=(const MyString&); cannot be overloaded
// 成员操作函数
// substr
MyString substr(size_t pos,const size_t n);
// append
MyString& append(const MyString&);
//insert
MyString& insert(size_t,const MyString&);
//assign 替换
MyString& assign(MyString&,size_t,size_t);
// erase 删除
MyString& erase(size_t,size_t);
//find_first_of 查找某一个字符 size_t 是非符号数的,重载
// 查找在字符串中第一个与str中的某个字符匹配的字符,返回它的位置。
//搜索从index开始,如果没找到就返回string::npos
int find_first_of(const char* str,size_t index=0);
int find_first_of(const char ch,size_t index=0);
int find_first_of(const MyString &,size_t index=0);
// 在字符串中查找第一个与str中的字符都不匹配的字符,返回它的位置。搜索从index开始。如果没找到就返回string::nops
int find_first_not_of(const char* str,size_t index=0);
int find_first_not_of(const char ch,size_t index=0);
int find_first_not_of(const MyString&,size_t index=0);
// swap
void swap(MyString& lhs,MyString& rhs);
// replace_all
MyString& replace_all(const char oldc,const char newc=NULL);
MyString& replace(size_t index,size_t num1,size_t num2,const char ch);
//find
int find(const char* str,size_t index=0);
int find(const MyString& str,size_t index=0);
int find(const char ch,size_t index=0); //private
private:
char *p_str;
size_t strLength;
}; #endif // MYSTRING_H
方法实现:
#include "MyString.h"
#include <cassert> // constructor
MyString::MyString():p_str(NULL),strLength(0){} MyString::MyString(const MyString &str)//
{
if(NULL == str.p_str)
{
return;
}
strLength = str.strLength;
p_str = new char[strLength+1];
strcpy(p_str,str.p_str);
}
MyString::MyString(const char *str)
{
if(NULL == str)
{
return;
}
strLength = strlen(str);
p_str = new char[strLength+1];
strcpy(p_str,str);
}
MyString::MyString(const size_t len,const char ch)
{
if(NULL == ch)
{
return;
}
strLength = len;
p_str = new char[strLength+1];
for(size_t i=0;i<strLength;i++)
{
p_str[i] = ch;
}
p_str[strLength] = '\0';// 因为strset以'\0'结束的
cout << p_str << " &&" << endl;
//strset(p_str,ch);
//cout << p_str[0] << ",,,"<<strlen(p_str) << "," << strLength << endl;
}
// destructor
MyString::~MyString()
{
delete[] p_str;
} // attributes
size_t MyString::length()// 字符串长度
{
return strLength;
}
bool MyString::isEmpty()// 返回字符串是否为空
{
return strLength==0?true:false;
}
const char* MyString::c_str()
{
return p_str;
}
// 为什么不是引用呢??? friend 使用在类里面进行声明的,外面就不需要了,而且友元函数不属于类的成员函数,所以不用MyString::
// ostream
ostream& operator<< (ostream& out,const MyString &str)
{
if(str.p_str != NULL)
{
out << str.p_str;
}
return out;
}
// istream,一个是const另一个不是,根据变还是不变
istream& operator>> (istream& in, MyString& str)
{
char tmp[100];// 临时字符串
if(in>>tmp)
{
delete[] str.p_str;
str.strLength = strlen(tmp);
str.p_str = new char[str.strLength+1];
strcpy(str.p_str,tmp);
}
return in;
}
// + 加
MyString operator+(const MyString& lhs,const MyString& rhs)
{
MyString ret;
ret.strLength = lhs.strLength + rhs.strLength;
ret.p_str = new char[ret.strLength+1];
strcpy(ret.p_str,lhs.p_str);
strcat(ret.p_str,rhs.p_str);
return ret;
}
// compare operations
bool operator==(const MyString& lhs,const MyString& rhs)
{
return strcmp(lhs.p_str,rhs.p_str)==0?true:false;
}
bool operator!=(const MyString& lhs,const MyString& rhs)
{
return strcmp(lhs.p_str,rhs.p_str)!=0?true:false;
}
bool operator<(const MyString& lhs,const MyString& rhs)
{
return strcmp(lhs.p_str,rhs.p_str)<0?true:false;
}
bool operator<=(const MyString& lhs,const MyString& rhs)
{
return strcmp(lhs.p_str,rhs.p_str)<=0?true:false;
}
bool operator>(const MyString& lhs,const MyString& rhs)
{
return strcmp(lhs.p_str,rhs.p_str)>0?true:false;
}
bool operator>=(const MyString& lhs,const MyString& rhs)
{
return strcmp(lhs.p_str,rhs.p_str)>=0?true:false;
}
// 成员函数实现运算符重载
// index operation
char& MyString::operator[](const size_t index)
{
if(index<0 || index>=strLength)
{
throw Outofbond() ;
}
return p_str[index];
}
const char& MyString::operator[](const size_t index)const
{
if(index<0 || index>=strLength)
{
throw Outofbond();
}
return p_str[index];
}
// = 赋值构造函数(判断是否是自身) 为什么要这样删除呢?
MyString& MyString::operator=(const MyString& other)
{
if(this != &other)
{
if(strLength<other.strLength)
{
delete[] p_str;
p_str = new char[other.strLength+1];
}
strLength = other.strLength;
strcpy(p_str,other.p_str);
}// 这样可能会产生多余的未释放的空间
return *this;
}
// += 相当于返回的是备份的,内部对象的销毁,不影响的 和 下面的完全不一样的
// MyString MyString::operator+=(const MyString& other)
// {
// if(NULL == other.p_str)
// {
// return *this;
// }
// MyString ret;
// ret.strLength = strLength + other.strLength;
// ret.p_str = new char[ret.strLength+1];
// strcpy(ret.p_str,p_str);
// strcat(ret.p_str,other.p_str);
// return ret;
// }
// 返回的是当前对象的引用,当前对象就在调用函数里,所以不会销毁的
// 判断一下是否是自身相加
MyString& MyString::operator+=(const MyString& other)
{
if(NULL == other.p_str)
{
return *this;
}
if(this == &other)
{
MyString copy(*this);
return *this += copy;
}// 必须判断是否相等的,而且要+=的,这样相当于调用了自身,但是这次直接下面去了,不进入if的
strLength += other.strLength;
//strLength *= 2;
char *p_old = p_str;
p_str = new char[strLength+1];
strcpy(p_str,p_old);
strcat(p_str,other.p_str);
delete[] p_old;// 删除旧的空间
return *this;
}
// 成员操作函数
// substr 返回应用是不行的,错误的;取从pos开始的n个字符组成的子串
//MyString& MyString::substr(size_t pos,const size_t n)
MyString MyString::substr(size_t pos,const size_t n)
{
if((pos+n)>=strLength)
{
throw Outofbond();
}
MyString ret;
ret.strLength = n;
//ret.p_str = new char[n+1];
ret.p_str = new char[ret.strLength+1]; //也可以
for(size_t i=0;i<n;i++)
{
ret.p_str[i] = p_str[pos+i];
}
ret.p_str[n] = '\0';
// for(size_t i=0;i<ret.strLength;i++)
// {
// ret[i] = (*this)[pos+i];
// cout << ret[i] << ",,";
// }// 也行的,利用刚刚重载的【】,这样更好,不用再次判断越界了,不知道为什么,报错误的
// ret[ret.strLength] = '\0';
return ret;
}
// append 同 += 追加到末尾
MyString& MyString::append(const MyString& other)
{
*this += other;// 利用刚刚那重载的+=
return *this;
}
//insert 从pos开始的插入other
MyString& MyString::insert(size_t pos,const MyString& other)
{
if(pos<0 || pos>=strLength)
{
throw Outofbond();
}
char *p_old = p_str;
strLength += other.strLength;
p_str = new char[strLength+1];
for(size_t i=0;i<pos;i++)
{
*(p_str+i) = *(p_old+i);
}
for(size_t i=pos;i<other.strLength+pos;i++)
{
*(p_str+i) = other.p_str[i-pos];
}
for(size_t i=other.strLength+pos;i<strLength;i++)
{
*(p_str+i) = p_old[i-other.strLength];
}
*(p_str+strLength) = '\0';
return *this;
}
//assign 替换 用other的POS开始的n对应替换this的pos开始的
MyString& MyString::assign(MyString&other,size_t pos,size_t n)
{
// if(pos<0 || pos>=strLength)
// {
// throw Outofbond();
// }
assert(pos>0 && pos<strLength);// assert 的好处
assert(pos+n<other.strLength);
if(strLength < pos + n)
{
char *p_old = p_str;
strLength = pos + n;
p_str = new char[strLength+1];
for(size_t i=0;i<pos;i++)
{
*(p_str+i) = *(p_old+i);
}
delete[] p_old;
}
for(size_t i=pos;i<pos+n;i++)
{
*(p_str+i) = other.p_str[i];
}
*(p_str+pos+n) = '\0';
return *this;
}
// erase 删除 这个方法并不是很好的,并没有释放所erase的空间,请看下面的
// MyString& MyString::erase(size_t pos,size_t n)
// {
// if((pos+n)>strLength)
// {
// throw Outofbond();
// }
// size_t index = pos + n;
// while(*(p_str+index)!='\0')
// {
// *(p_str+index-n) = *(p_str+index);
// ++index;
// }
// *(p_str+index-n) = '\0';
// return *this;
// }
// erase 删除 从pos开始的n个字符
MyString& MyString::erase(size_t pos,size_t n)
{
if((pos+n)>strLength)
{
throw Outofbond();
}
char *p_old = p_str;
strLength -= n;
p_str = new char[strLength+1];
for(size_t i=0;i<pos;i++)
{
p_str[i] = p_old[i];
}
for(size_t i=pos;i<strLength;i++)
{
p_str[i] = p_old[i+n];
}
*(p_str+strLength) = '\0';
return *this;
}
//find_first_of 查找某一个字符 size_t 是非符号数的
// 查找在字符串中第一个与str中的某个字符匹配的字符,返回它的位置。
//搜索从index开始,如果没找到就返回string::npos
int MyString::find_first_of(const char* str,size_t index)
{
if(NULL == str || index >=strLength)
return npos;
int tmp_len = strlen(str),j;
size_t flag,min_index = INI_MAX;
for(j=0;j<tmp_len;j++)
{
flag = npos;
for(size_t i=index;i<strLength;i++)
{
if(str[j] == p_str[i])
{
flag = i;
break;
}
}
// indexs[j] = flag;
if(flag != npos)
{
min_index = min_index<flag?min_index:flag;
}
}
// for(j=0;j<tmp_len;j++)
// {
// if(indexs[j]!=npos)
// min = min<indexs[j]?min:indexs[j];
// }
if(min_index == INI_MAX)
{
return npos;
// min_index = npos;
// cout << "---npos----" << min_index << ",,,,";
}
return min_index;
}
int MyString::find_first_of(const char ch,size_t index)
{
if(NULL == ch || index >=strLength)
return npos;
int j;
size_t flag = npos;
for(size_t i=index;i<strLength;i++)
{
if(ch == p_str[i])
{
flag = i;
break;
}
}
return flag;
}
int MyString::find_first_of(const MyString& str,size_t index)
{
if(NULL == str || index >=strLength)
return npos;
int j;
size_t flag,min_index = INI_MAX;
for(j=0;j<str.strLength;j++)
{
flag = npos;
for(size_t i=index;i<strLength;i++)
{
if(str[j] == p_str[i])
{
flag = i;
break;
}
}
if(flag != npos)
{
min_index = min_index<flag?min_index:flag;
}
}
if(min_index == INI_MAX)
{
return npos;
}
return min_index;
}
// 在字符串中查找第一个与str中的字符都不匹配的字符,返回它的位置。
//搜索从index开始。如果没找到就返回string::nops O(N^2)
int MyString::find_first_not_of(const char *str,size_t index)
{
if(NULL == str || index >=strLength)
return npos;
size_t i=0,j=0;
size_t tmp_len = strlen(str);
for(i=index;i<strLength;i++)
{
for(;j<tmp_len;j++)
{
if(p_str[i]==str[j])
break;
}
if(j==tmp_len)
break;// 根据跳出的内层for的条件判断,找到即结束循环
}
if(i==strLength)
return npos;// 未找到,// 根据跳出的内层for的条件判断,找到即结束循环
return i;
}
int MyString::find_first_not_of(const MyString& str,size_t index)
{
if(NULL == str || index >=strLength)
return npos;
size_t i=0,j=0;
for(i=index;i<strLength;i++)
{
for(;j<str.strLength;j++)
{
if(p_str[i]==str[j])
break;// 如果相等 本轮i就无效了,进行下一轮
}
if(j==str.strLength)
break;// 根据跳出的内层for的条件判断,找到即结束循环
}
if(i==strLength)
return npos;// 未找到,// 根据跳出的内层for的条件判断,找到即结束循环
return i;
}
int MyString::find_first_not_of(const char ch,size_t index)
{
if(NULL == ch || index >=strLength)
return npos;
size_t i=0;
for(i=index;i<strLength;i++)
{
if(p_str[i]!=ch)// 跟上面的略微不同,找一个不等就可以了
break;
}
if(i==strLength)
return npos;// 未找到,// 根据跳出的内层for的条件判断,找到即结束循环
return i;
}
// swap 都得变得,所以非const
void MyString::swap(MyString& lhs,MyString& rhs)
{
lhs.strLength ^= rhs.strLength;
rhs.strLength ^= lhs.strLength;
lhs.strLength ^= rhs.strLength;
char *p_tmp = rhs.p_str;
rhs.p_str = lhs.p_str;
lhs.p_str = p_tmp;
}
// replace_all 这个东西还是不太好弄的啊,不是很理想
MyString& MyString::replace_all(const char oldc,const char newc)
{
if(NULL == oldc)
{
return *(this);
}
for(size_t i=0;i<strLength;i++)
{
if(p_str[i] == oldc)
{
p_str[i] = newc;
}
}
return *(this);
}
MyString& MyString::replace(size_t index,size_t num1,size_t num2,const char ch)
{ }
// find 函数
int MyString::find(const char* str,size_t index)
{
assert(str!=NULL&&index<strLength);
// kmp 中的getnext函数
size_t len = strlen(str);
size_t next[len+1];
size_t j,k;
next[0] = npos;
j = 0;
k = npos;
while(j<len)
{
if(k==npos || str[j]==str[k])
{
j++;
k++;
next[j] = k;
}
else
k = next[k];
}
// kmp 算法
k = index;
j = 0;
while(p_str[k]!='\0')
{
if(j==0 || p_str[k]==str[j])
{
k++;
j++;
}
else
{
j = next[j];// 消除指针回溯
}
if(str[j] == '\0')//匹配成功
return k-j;
}
return npos;
}
int MyString::find(const MyString& str,size_t index)
{
// if(this == &str)
// {
// MyString other(*this);
// find(other,index);
// }
assert(NULL!=str && index<strLength);
// kmp 中的getnext函数 size_t next[str.strLength+2];
size_t j,k;
next[0] = npos;
j = 0;
k = npos;
while(j<str.strLength)
{
if(k==npos || str.p_str[j]==str.p_str[k])
{
j++;
k++;
next[j] = k;
}
else
k = next[k];
}
int i;
for(i=1;i<=j;i++)
cout << next[i] << ",";
// kmp 算法
k = index;
j = 0;
while(p_str[k]!='\0')
{
if(j==0 || p_str[k]==str.p_str[j])
{
k++;
j++;
}
else
{
j = next[j];// 消除指针回溯
}
if(str.p_str[j] == '\0')//匹配成功,不知道为什么调用自身的str[]重载总是报错的
return k-j;
}
if(str.p_str[j] == '\0')// 同一个字符串
return k-j;
return npos;
}
int MyString::find(const char ch,size_t index)
{
assert(NULL!=ch && index<strLength);
for(size_t i=index;i<strLength;i++)
{
if(p_str[i] == ch)
return i;
}
return npos;
}
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.判断输入的用户名和密 ...
随机推荐
- 改进后的向量空间模型(VSM)
我们採用更加形式化的定义,并採用稍大一些的样例来展示怎样使用基于数据集频率的权重.相应于一个给定的词项,其权重使用IDF(逆文档频率)来计算. 为了给每篇文档建立一个相应的向量,能够考虑例如以下定义. ...
- Spring延迟加载
如下内容引用自:http://www.cnblogs.com/wcyBlog/p/3756624.html 1.Spring中lazy-init详解ApplicationContext实现的默认行为就 ...
- 【Sprint3冲刺之前】TDzhushou软件项目测试计划书
TDzhushou软件测试计划文档 文档编号:2014-5-8 产品版本:1.1 产品名称:TDzhushou 文 档 作 者: 解凤娇 日期:2014-5-4 软件测试计划 目录 第一章 ...
- 【每日Scrum】第七天(4.28)Sprint2总结性会议
本次会议主要是演示了一下本组项目的各项功能,每个人负责那一块儿功能由本人来负责说明和演示,确定alpha版本的发布时间,并且分派了各组员的文档负责情况,上图是会议记录,下面我详细介绍一下我组分派情况: ...
- python--函数程序分析
写函数,用户传入修改的文件名,与要修改的内容,执行函数,完成整个文件的批量修改操作 import os #加载模块 def xiu(a,b,c): #三个接受值的形参 f = open(a,encod ...
- ffmpeg编码常见问题排查方法
播放问题排查: 一旦我们遇到视频播放不了,第一件事,就是要找几个别的播放器也播放看看,做一下对比测试,或者对码流做一些基础分析,以便更好的定位问题的源头,而各个平台比较常见的播放/分析工具有如下几个: ...
- EasyDarwin开源流媒体服务器内存管理优化
-本文由EasyDarwin开源团队成员Fantasy贡献 前言 最近在linux上跑EasyDarwin发现一个很奇怪的问题,当有RTSPSession连接上来的时候,发现进程的虚拟内存映射一下就多 ...
- Problem binding to [bigdata-server-01:9000] java.net.BindException: Cannot assign requested address;
If the port is "0", then the OS is looking for any free port -so the port-in-use and port- ...
- three supported reliability levels: * End-to-end * Store on failure * Best effort
https://github.com/cloudera/flume/blob/master/flume-docs/src/docs/UserGuide/Introduction === Reliabi ...
- mysql 修改语法格式
1.修改字段注释格式 alter table {table} modify column {column} {type} comment '{comment}';