用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的接口的更多相关文章

  1. Java字符串String 集合的迭代器

    Java字符串String 我们知道Java的字符窜是Immutable(不可变)的,一旦创建就不能更改其内容了:平常我们对字符串的操作是最多的,其实对字符串的操作,返回的字符串都是新建的字符串对象, ...

  2. C# 字符串string类型转换成DateTime类型 或者 string转换成DateTime?(字符串转换成可空日期类型)

    在c#中,string类型转换成DateTime类型是经常用到的,作为基本的知识,这里在此做个小结.一般来说可以使用多种方法进行转换,最常用的就是使用Convert.ToDateTime(string ...

  3. 字符串string类型转换成DateTime或DateTime?类型

    常用的Convert.ToDateTime方法 //将含有正确日期格式的string类型转换成DateTime类型 string strDate = "2014-08-01"; D ...

  4. python 字符串 string

    字符串 string 语法: a = 'hello world!' b = "hello world!" 常用操作: 1.乘法操作是将字符串重复输出2遍 >>> ...

  5. C#如何生成JSON字符串提交给接口(服务器)

    C#如何生成JSON字符串提交给接口(服务器)   第一章:C#如何拿到从http上返回JSON数据? 第二章:C#如何解析JSON数据?(反序列化对象) 第三章:C#如何生成JSON字符串?(序列化 ...

  6. C#字符串string以及相关内置函数

    C#字符串string函数 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享. ...

  7. Spring关于使用注解@Configuration去配置FormattingConversionServiceFactoryBean来实现自定义格式字符串处理无效的问题(未找到是什么原因造成的)

    说明:在Spring MVC和Spring Boot中都能正常使用. 首先,我实现了一个自定义的注解,@Trimmed去除字符串String的前后空格. 如果是在Spring MVC的XML配置中,可 ...

  8. openresty开发系列18--lua的字符串string操作

    openresty开发系列18--lua的字符串string操作 string的相关操作 1)string.upper(s)接收一个字符串 s,返回一个把所有小写字母变成大写字母的字符串.print( ...

  9. ES6让字符串String增加了哪些好玩的特性呢?

    确实因为现在天气变热了,所以一天天的这么写我也很累.所以如果阅读的时候有什么错误还请大家指出来,不好意思.学习永无止境. OK,今天继续讲解ES6系列知识 学过上一节的解构赋值就知道,ES6确实给我们 ...

随机推荐

  1. JAVA中JavaBean对象之间属性拷贝的方法

    JAVA中JavaBean对象之间的拷贝通常是用get/set方法,但如果你有两个属性相同的JavaBean或有大部分属性相同的JavaBean,对于这种情况,可以采用以下几个简便方法处理. 下面对这 ...

  2. 线上服务器CPU100%排查

    某服务器上部署了若干tomcat实例,即若干垂直切分的Java站点服务,以及若干Java微服务,突然收到运维的CPU异常告警. 问:如何定位是哪个服务进程导致CPU过载,哪个线程导致CPU过载,哪段代 ...

  3. Oracle PL/SQL基础

    1.下载sql developer数据库连接可视化工具 连接地址:点我下载 下载完成,安装有Java环境,解压即可运行,也可以在linux系统中运行.

  4. hive 取排行第二的工资

    CREATE TABLE employee( id INT , salary INT ); INSERT INTO employee , UNION ALL , UNION ALL ,; SELECT ...

  5. pandas分组聚合案例

    美国2012年总统候选人政治献金数据分析 导入包 import numpy as np import pandas as pd from pandas import Series,DataFrame ...

  6. k8s入门教程

    1. k8s概述 Kubernetes(简称K8S) 是Google开源的分布式的容器管理平台,方便我们在服务器集群中管理我们容器化应用. 教程主要介绍怎么使用阿里云容器服务(kubernetes版本 ...

  7. 缓存模块redis

    1.安装 安装 下载 :wget http://download.redis.io/releases/redis-3.2.8.tar.gz 解压:tar xzf redis-3.2.8.tar.gz ...

  8. git账号失效问题解决

    linux开发机上,使用某人账号,进行代码同步.该员工离职,导致该git账号不可用. 此时需要完成3步配置: 1.生成新的公私秘钥:在~/.ssh/config中把私钥文件路径 append到文件末尾 ...

  9. Zookeeper3.4.14集群搭建

    环境: 3台centos7.4 1. 下载release:wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3. ...

  10. Linux 下源码安装ngnix

    版本说明: NGINX 版本1.12.0 pcre-8.40 zlib-1.2.11 openssl-1.1.0i   安装过程 # ./configure  --prefix=/usr/ngnix  ...