自定义实现字符串string的接口
用char*管理String类的内存,new动态分配,在析构函数中delete char*指向的new出来的内存,一个string类需要实现那些接口可参考标准库里的string: http://www.cplusplus.com/reference/string/string/
- 实现思路是:在创建String、String需要伸缩(如赋值时需要调整大小、字符串相加也需要更大的空间)时重新new内存,并释放掉原有内存;标准库string的空间是预先分配的,有多余的空间可用,如果string需要伸缩,就开辟新的内存空间。
- >>重载的思路是:用cin.getline来读取标准输入到字符指针指向的空间——空间有个预设的大小,如100,可以接收包含有空格的字符串
- String初始化为空字符串("\0"或 ""是等价的),也需要new字符数组,这样才能delete,如果用char *data="\0",不能用delete释放不是new出来的内存
- []需要重载两个版本,const版本 const char& operator[](size_t index) const; const成员函数的this指针隐式的转换为指向常量的指针: operator(const String *this, size_t index),const对象只能调用const menber function
- 不需要重载解引用*和取地址&,它们对自定义的类型也支持
- +=调用了operator+,问为什么operator+要返回引用,而不能返回对象?
- 没有实现重载的relational operators
- 相比标准库,自定义的String实现的接口很少,似乎什么都做不了,只能创建,赋值,输出,访问元素,甚至连标准库里的string开发中也不好用:为什么大多数的C++的开源库都喜欢自己实现一个string?
- new管理内存是否存在memory leak,是否有隐含的错误?
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cstdio>
#include<complex>
#include<new>
#include<memory>
#include<exception>
using namespace std;
// interfaces should supported
//用char*管理内存
class String
{
public:
String();
String(const char*s);
String(size_t n, const char c);//用字符c填充String
String(const String&s);
String& operator=(const String&rhs);
String& operator=(const char*c);
char& operator[](size_t index);//要提供[]的两个版本
const char& operator[](size_t index)const;
String & operator*();//解引用重载是多余的,语言本身支持对所有类型的指针解引用,包括了自定义类型
String& operator+(const String&rhs);
String& operator+=(const String&rhs);
bool operator==(const String&rhs);
friend bool operator<(const String&lhs, const String&rhs);
friend ostream& operator<<(ostream& os, const String&rhs);
friend istream& operator>>(istream& in, String&rhs);
size_t size(); //如果是size_t length()会导致。。。。。
bool empty();
const char* c_str();
~String();
private:
char * data;
size_t length; };
String::String() //类外面定义menber function ,域作用符
{
this->data = new char[](); //空字符串 ,strlen对data运算得到的长度为0
data[] = '\0';
(*this).length = ;
}
String::String(const char*s) //允许implicit类型转换
{
// 不能用data=s;这导致创建的String对象与s共享了字符,而不是副本
length = strlen(s);
data = new char[length + ]();//value initialization,申请了字符指针指向的内存区域
strcpy(data, s);
*(data + length) = '\0';
}
String::String(size_t n, const char c)
{
length = n;
data = new char[length + ]();
for (size_t i = ; i < length;i++)
{
*(data + i) = c;
}
*(data + length) = '\0';
}
String::String(const String&s)
{
length = s.length;
data = new char[length + ](); //untill deconstructor to destory newed memory
for (size_t i = ; i < length;i++)
{
data[i] = s.data[i];
}
data[length] = '\0';
}
String& String::operator=(const String&rhs)
{
if (this->data == rhs.data) return *this;// 支持*this==rhs的关系比较操作吗? //assign 不是初始化,不需要申请内存空间,拷贝构造需要 ,但是原String与rhs大小可能不一样
delete[]data; //会导致重复删除data所指内存吗?? length = rhs.length;
data = new char[length + ]();
//如果发生异常 if (data == NULL) throw "allocate memory failed in copy ctr";
for (size_t i = ; i < length; i++)
{
data[i] = rhs.data[i];
}
data[length] = '\0';
}
char& String::operator[](size_t index)
{
if (index >= length||index<) throw "out of range";
return data[index];//如果data指向的字符串为"dhaj"这种不可修改的,会导致返回的引用不能有s[i]='c'的修改操作
}
String& String:: operator*()
{
if (this == NULL) throw "dereferrence null pointer ";
return *this;
}
String& String::operator+(const String&rhs)//a+b形式,也不改变a
{
String s;//不可伸缩,不能用来存a+b的结果
int len = strlen(this->data) + strlen(rhs.data);
char *p = new char[len + ]();
for (size_t i = ; i < strlen(this->data); i++)
{
p[i] = this->data[i];
}
for (int j = strlen(this->data),i=; j < len; j++,i++)
{
p[j] = rhs.data[i];
}
p[len] = '\0';
String *t = new String(p); //new了一个p,一个t,可以释放掉p,因为t是p的副本
delete[]p;
return *t;//返回了堆上的引用,再c=a+b这种使用后,c是会析构的,但中间这个看不见的对象不会析构
}
String& String::operator+=(const String&rhs)
{
*this = *this + rhs;
//释放掉原来的a,申请新空间
return *this;
}
bool String::operator==(const String&rhs)//比较是否相等,而不是相同
{
if (this->length != rhs.length) return false;
int i = ;
for (; (*this).data[i] == rhs.data[i]; i++);
if (i != (rhs.length + )) return false;
else return true;
}
bool operator<(const String&lhs, const String&rhs)
{
return true;
}
ostream& operator<<(ostream& os, const String&rhs) //申明为友元函数。调用方式为cout<<s,申明为men fun,调用形式为s<<cout
{
os << rhs.data;//输出null pointer会未定义行为
return os;
}
istream& operator>>(istream& is, String&rhs)
{//输入一个字符串到字符指针,字符指针需要预先分配一定大小的空间,如何根据输入的字符串调整空间大小
delete[]rhs.data;
rhs.data = new char[]();
is.getline(rhs.data, );//最后位置自动置为'\0',所以最多存49个字符,可接收空格
rhs.length = strlen(rhs.data);
return is;
}
size_t String::size()
{
return length;
}
bool String::empty()
{
if (length == ) return true;
else return false;
}
const char* String::c_str()//返回指向对象局部部分的引用,指针,能用来修改原对象吗?
{//如果为空串,也要返回data
return data; }
String::~String()
{ // 析构会发生错误吗?
//String创建时会new内存,当程序结束或局部String对象退出作用域时调用析构函数,释放该内存
delete[]data; //如果String不是new出来的, 指针p指向它,delete p会导致错误,new出来的可以调用delete,这时会调用~String
data = NULL;
} //int main()
//{
// String s;
// cout << s << endl;
// cout << strlen(s.c_str()) << endl;
// String s1 = "whah";
// cout << s1 << endl;
// String s2 = s1;
// cout <<"s2 length:"<< s2.size() << endl;
// s = s2;
// cout << "用s2赋值后的s: " << s << endl;
// String s3(10, 'c');
// cout << "字符填充初始化s3: " << s3 << " " << "s3 len= " << s3.size() << endl;
// s3[0] = 'a';
// cout << "下标修改s3后: " << s3 << endl;
// String s4 = s2 + s3+"ad"; //支持连续的+
// cout << s4 << endl;
// String *sp = &s4;
// cout << *sp << endl;
// cout << strlen((*sp).c_str()) << endl;
// String *q = new String(*sp);
// cout << *q << endl;
// delete q;
//
// char *sq = const_cast<char*> (s4.c_str());
// sq[0] = 'l';
// cout << sq << endl;
// cout << s4 << endl;
// const char *cptr = s2.c_str();
// string s5 = "";
// string s6 = "\0";
// cout << s5 << "**" << s6 << s5.size() << s6.size() << endl;
// string str = "jadj";
// char *sptr = const_cast<char *> (str.c_str());
// sptr[0] = 'd';
// cout << sptr << " " << str << endl;
// String s7(s2);
// s7 += s4;
// cout << "s7: " << s7.size() << s7 << endl;
// const String s8("daj");
// //s8[0]; 对const对象的[]调用,不能用non-const menber版本的operator[],要提供 const char& operator[]() const重载版本
// //s8 = "djwajk0";
//} int main()
{
string s2;
cin >> s2;
cout << s2 << endl;
String s, s1;
cin >> s >> s1;//用Enter间隔字符串,可接含有空格的字符串
cout << s <<"\n"<< s1 << endl;
cout << s1.size() << endl;
}
String类
自定义实现字符串string的接口的更多相关文章
- Java字符串String 集合的迭代器
Java字符串String 我们知道Java的字符窜是Immutable(不可变)的,一旦创建就不能更改其内容了:平常我们对字符串的操作是最多的,其实对字符串的操作,返回的字符串都是新建的字符串对象, ...
- C# 字符串string类型转换成DateTime类型 或者 string转换成DateTime?(字符串转换成可空日期类型)
在c#中,string类型转换成DateTime类型是经常用到的,作为基本的知识,这里在此做个小结.一般来说可以使用多种方法进行转换,最常用的就是使用Convert.ToDateTime(string ...
- 字符串string类型转换成DateTime或DateTime?类型
常用的Convert.ToDateTime方法 //将含有正确日期格式的string类型转换成DateTime类型 string strDate = "2014-08-01"; D ...
- python 字符串 string
字符串 string 语法: a = 'hello world!' b = "hello world!" 常用操作: 1.乘法操作是将字符串重复输出2遍 >>> ...
- C#如何生成JSON字符串提交给接口(服务器)
C#如何生成JSON字符串提交给接口(服务器) 第一章:C#如何拿到从http上返回JSON数据? 第二章:C#如何解析JSON数据?(反序列化对象) 第三章:C#如何生成JSON字符串?(序列化 ...
- C#字符串string以及相关内置函数
C#字符串string函数 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享. ...
- Spring关于使用注解@Configuration去配置FormattingConversionServiceFactoryBean来实现自定义格式字符串处理无效的问题(未找到是什么原因造成的)
说明:在Spring MVC和Spring Boot中都能正常使用. 首先,我实现了一个自定义的注解,@Trimmed去除字符串String的前后空格. 如果是在Spring MVC的XML配置中,可 ...
- openresty开发系列18--lua的字符串string操作
openresty开发系列18--lua的字符串string操作 string的相关操作 1)string.upper(s)接收一个字符串 s,返回一个把所有小写字母变成大写字母的字符串.print( ...
- ES6让字符串String增加了哪些好玩的特性呢?
确实因为现在天气变热了,所以一天天的这么写我也很累.所以如果阅读的时候有什么错误还请大家指出来,不好意思.学习永无止境. OK,今天继续讲解ES6系列知识 学过上一节的解构赋值就知道,ES6确实给我们 ...
随机推荐
- [HDU 3625]Examining the Rooms (第一类斯特林数)
[HDU 3625]Examining the Rooms (第一类斯特林数) 题面 有n个房间,每个房间有一个钥匙,钥匙等概率的出现在n个房间内,每个房间中只会出现且仅出现一个钥匙.你能炸开门k次, ...
- Codeforces - 1195D2 - Submarine in the Rybinsk Sea (hard edition) - 组合数学
https://codeforc.es/problemset/problem/1195/D2 很明显可以看出,任意一个长度为\(l_1\)的数串\(s_1\)和任意一个长度为\(l_2\)的数串\(s ...
- HDU 5441 Travel (离线dsu)
<题目链接> 题目大意:$n$个点,$m$条边,每条边具有对应的权值,然后进行$k$次询问,每次询问给定一个值,所有权值小于等于这个的边所对应的点能够相连,问每次询问,这些能够相互到达的点 ...
- rabbitmq部署安装
1.安装rabbitmq需要提前安装erlang,相关下载地址:http://www.erlang.org/downloads,需要注意:默认安装的RabbitMQ 监听端口是5672 启动和 ...
- 剑指offer学习--初级c++面试题
定义一个空的类型,里面没有任何成员函数和成员变量,对该类型求sizeof,得到的结果是多少? 答案是1.空类型中的实例中不包含任何信息,本来求sizeof应该是0,但是当我们声明该类型的实例的时候,他 ...
- JavaScript 内置对象 Array 数组
Array 数组 1.创建数组 构造函数 new Array() 小括号内可以是数组元素个数,也可以是数组项 数组字面量表示法 var arr = [1,2,3,4,5]; 2.数组长度 arr.le ...
- linux系统使用和优化的原则
- zabbix3.4.8配置自动发现主机并监控
一. 自动发现功能简介 Zabbix服务器端通过网络或者主机名等方式进行客户端的扫描发现,从进行加入到监控的主机队列中,适用于批量加入多主机监控的场景. 二. 自动发现功能实施 ...
- php pdo_mysql扩展安装
本文内容是以 CentOS 为例,红帽系列的 Linux 方法应该都是如此,下面就详细说明步骤,在这里严重鄙视哪些内容??隆⑺档脑悠咴影说挠泄 PDO 编译安装的文章. 1.进入 PHP 的软件包 p ...
- SVN中trunk,branches,tags的使用明细--项目代码的管理
SVN在项目开发过程中有两种模式: 第一种:Subversion有一个很标准的目录结构,是这样的.比如项目是proj,svn地址为svn://proj/,那么标准的svn布局svn://proj/|+ ...