String类的实现

String类的实现

C++封装了一种新的数据类型 --- 字符串类型 String
该类型在库string中对string类进行了封装,库内实现了对字符串的各种操作运算符的重载
如: “ = ” ,“ += ” , “ + ” , “==” , “!=” , "<<" , ">>" 等运算符的重载。



运算符重载格式:


<函数返回值类型> operator <运算符> (<函数形参>)
{
//函数体
}



在实现该String类之前先了解一下深拷贝和浅拷贝


浅拷贝:只是拷贝了指针的值,在拷贝是并没有为对象开辟新的内存空间,而是拷贝的对象的指针指向了被拷贝的对象的内存空间,这时两个对象的指针指向了同一块内存空间。
深拷贝:和浅拷贝刚好相反,拷贝时重新开辟一块自己的内存空间,将被拷贝对象的数据拷贝进来,两者的指针分别指向各自的内存空间。

深浅拷贝存在的问题
  由于浅拷贝只是拷贝了指针的值,这样导致一个对象被释放时,该段空间将被直接delete,而危险的是另一个或多个
拷贝对象不知道这块内存已经被释放,再次访问时将会崩溃。深拷贝避开了这一问题,给各自的指针重新开辟了内存空间
导致同一份数据在内存中保留了多份,这样会造成内存空间极大的浪费。为解决这一问题,我们引入了引用计数。

引用计数:
  在开辟空间时多开辟一个字节专门存放引用计数(count)的值,当第一次为对象开辟空间时初始化count为1 , 当有对象拷贝该对象时
不用重新开辟内存空间,直接让该指针指向这块内存空间,同时引用计数count的值+1即可。当析构一个对象时判断该对象的引用计数的值
如果大于1,则证明有其他对象也在应用这块数据,此时引用计数-1即可,当引用计数为1时,直接释放这块空间。




下面具体实现String类(深拷贝格式)


#include <iostream>
#include <cstring>
using namespace std;


class String
{
public:
String(char* _str = "")
:str(new char[strlen(_str) + 1])  //为字符串多开辟一个空间放/0
{
strcpy(str, _str);
}
String(const String& s)
:str(new char[strlen(s.str)+1])
{
cout << "拷贝构造" << endl;
strcpy(str, s.str);
}
~String()
{
if (!str)
{
delete[]str;
str = NULL;
}
}
String& operator+(const String& s)   //对+运算符重载 (实现字符串的拼接)
{
String tmp;
tmp.str = new char[strlen(s.str) + 1];
strcpy(tmp.str, s.str);
delete[]this->str;
this->str = new char[strlen(tmp.str)+strlen(s.str)+1];
strcpy(this->str, tmp.str);
strcat(this->str , s.str);
return *this;
}
String& operator=(const String& s)   //对赋值运算符重载
{
if (0 == strcmp(this->str, s.str))
{
return *this;
}
delete[]this->str;
this->str = new char[strlen(s.str) + 1];
strcpy(this->str, s.str);
return *this;
}
bool operator==(const String& s)     //重载 == 运算符 
{
if (0 == strcmp(this->str, s.str))
{
return true;
}
else
return false;
}
String& operator+=(const String& s)  //重载 += 运算符 
{
if (0 == strlen(s.str))
{
return *this;
}
String tmp;
tmp = new char[strlen(this->str) + 1];
strcpy(tmp.str , this->str);
delete[]this->str;
this->str = new char[strlen(tmp.str) + strlen(s.str) + 1];
strcpy(this->str, tmp.str);
strcat(this->str , s.str);
return *this;
}
friend ostream& operator <<(ostream& os, const String& s);  //重载输出运算符(定义为友元函数实现)
private:
char* str;
};
ostream& operator<<(ostream& os, const String& s)  // << 运算符重载
{
os << s.str;
return os;
}




String类的实现(引用计数格式)


class Mystring
{
public:
Mystring(char* _str = "")
:str(new char[strlen(_str) + 1 + 1])  //在原有的基础上多申请一个空间用于存放引用计数的值
{
strcpy(str, _str);
str[strlen(str) + 1] = '1';      // 将引用计数存放在字符串的最后一个位置,初始化为 '1'
}
Mystring(const Mystring& s)
:str(s.str)
{
str[strlen(str) + 1] += 1;       //当拷贝对象时该引用计数值加1
}
~Mystring()
{
if (this->str[strlen(this->str) + 1] > '1')  //析构时判断引用计数的值 是否大于 '1',大于则减1
{
this->str[strlen(this->str) + 1] --;  
this->str = NULL;
}
else
{
delete[]this->str;                  //如果引用计数的值为1则直接释放空间
this->str = NULL;
}
}
friend ostream& operator <<(ostream& os, const Mystring& s); //将 << 运算符申明为友元函数
public:
char* str;
};
ostream& operator <<(ostream& os, const Mystring& s)
{
os << s.str;
return os;
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值