您的位置:首页 > 其它

深拷贝与写实拷贝----string

2017-03-26 17:55 375 查看

摘要

学过或者了解过C++都知道,,,在C++中面向对象实现一个类 、、、的时候必须要考虑的就是

【深浅拷贝】的问题 ??

所以我写了这篇文章来简要的讲述一下C++中深浅拷贝的问题以及由此引发的 另一个 概念【写实拷贝】

概念的解析

所谓的深浅拷贝就是

C++中;;;;;定义一个类的时候;;;

其拷贝构造函数、、、还有赋值运算符的重载 的不同的实现方法;;;

当一个类的成员变量中带有的是 指针;;;

当使用这个类对象拷贝生成一个对象的的时候、、、如果直接赋值的话,,,,,类析构的时候就会出现问题;;;

所以在这种时候 我们就需要来考虑深拷贝的问题;;;;

关于深拷贝的问题、、、大致主要有两种的方法:
方法1、
直接重新申请一段相同大小的空间、、、并赋值成相同的值 ;;;

这就是直接的深拷贝;

方法2、
在类的成员变量中加上一个 【引用计数 】用来表示当前有多少个对象在公用一段空间

类析构时、(要是引用计数为1 直接释放这段空间 )(否则的话就将这个对象的成员变量的指针置为NULL)

这种方法 就是 带有引用计数的浅拷贝的 实现深拷贝

【灰常的重要】

但是上述的方法2 虽然实现了 深拷贝 、、、但是还遗留了一个很大的问题;;;

假设有 4 个string类的对象 a b c d;公用的是 同一段的空间

现在要对 对象a 的内容进行修改、、、、
但是要是修改了 a的 内容 b c d的内容也会被修改(因为它们用的是同一段空间)

所以也就出现了 【写实拷贝】这个 概念》》》》

当遇到上述这种情况下、、、、谁 改变 就对谁进行拷贝 ------这就是 写实拷贝

上述的两种方法
Windows系统下的编程环境使用的是 方法1
Linux系统下是用的是 方法2

通常情况下、、、、、我们都是使用的是 string来演示实现 深拷贝、、、与写实拷贝的

代码的实现

下面我来实现这段代码的实现

#pragma  once
#include <assert.h>
//说道string类的两个主要考点就是
//深拷贝
//浅拷贝   写实拷贝 ()

//深拷贝
class String
{
public:
String(const  char  * str = "")
{
//要是传进来的字符串为 NULL
if(str == NULL)
{
//我们需要创建一个内容为 /0的字符串
_str  =new char [1];
*_str  = '/0';
}
else
{
//否则,,,开辟一个长度为 str长度+1;
_str  = new char [strlen(str)+1];
strcpy(_str,str);
}
}

//深拷贝的拷贝构造函数
//String(const  String &  str)
//	:_str(new char[strlen(str._str)+1])
//{
//	//先为字符串开辟一个空间
//	//将内部的数据拷贝
//	strcpy(_str,str._str);
//}

//简介版 的拷贝构造函数

String (const String &  str)
:_str(NULL)//现将当前的对象的字符串的指针赋为空 ,,,必须要写
{
//使用的是 str内部的字符串的指针,,来构造一个新的对象 str1;
String  str1(str._str);
//将当前的对象的_str  与  重新生成的新对象的_str 交换
swap(_str,str1._str);
}

//深拷贝的赋值运算符的重载
//String & operator = (const  String  &  str)
//{
//	if(this!= &str)
//	{
//		//开辟一个空间
//		char *  tmp  =new char[strlen(str._str)+1];
//		//将原来的空间释放
//		delete[]_str;
//		//将内容拷贝到所开辟的位置
//		strcpy(tmp,str._str);
//		//将开辟的空间给当前的类
//		_str = tmp;
//	}
//	return *this;
//}

//简介版 的赋值运算符的重载
String &    operator =(const  String  &  str)
{
//防止自己给自己赋值
if(this  != &  str)
{
String str1(str);//使用拷贝构造函数  ,,,来生成一个新的对象
//先将当前对象的_str释放 ,,,,并且赋值成 NULL
delete[]  _str;
_str = NULL;
swap(_str,str1._str);
}
return  *this;
}
~String()
{
if(_str != NULL)
{
delete []  _str;
}
_str   =NULL;
}

//重载【】
char & operator[](size_t n)
{
assert(n < strlen(_str) );
return  *(_str+n);
}
protected:
char  *_str;
};

//引用计数的浅拷贝     写实拷贝
class StringS
{
public:
StringS(const  char  * str = "")
{
//要是传进来的字符串为 NULL
if(str == NULL)
{
//我们需要创建一个内容为 /0的字符串
_str  =new char [1];
*_str  = '/0';
}
else
{
//否则,,,开辟一个长度为 str长度+1;
_str  = new char [strlen(str)+1];
strcpy(_str,str);
}
_count = new int(1);
}

//拷贝构造函数
StringS(const  StringS &  str)
:_str (str._str)
,_count(str._count)
{
(*_count)++;
}
//带有引用计数的赋值运算符的重载
StringS &  operator=( const StringS  &  str)
{
if(_str !=  str._str)
{
if(*_count == 1)
{
delete[] _str;
_str  =  str._str;
}
else
{
(*_count)--;
_str  = str._str;
}
_count  = str._count;
(*_count) ++;
}
return  *this;
}
~StringS()
{
if(*_count == 1)
{
delete[] _str;
delete _count;
}
else
{
(*_count) --;
}
_str = NULL;
_count =NULL;
}

//写实拷贝
//当某个对象要进行 写的话   ,,,就要对其 单独进行拷贝
char & operator[](size_t  n)
{
assert(n < strlen(_str) );
if(*_count != 1)//如果这个数 多个 对象使用的话
{
char  *  tmp  = new  char[strlen(_str)+1];
strcpy(tmp,_str);
_str  =  tmp;
(*_count)--;
_count  = new int(1);
}
return *(_str+n);
}
protected:
char *  _str;
int  *  _count ;//表示的是 引用计数

};
void testString()
{
String  st(NULL);
String  st1;
String  st2("we are happy");
String  st3(st2);
st1 = st3;
}
void testStringS()
{
StringS  st(NULL);
StringS  st1;
StringS  st2("we are happy");
StringS  st3(st2);
st1 = st3;
st2[2];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息