了解过C++语言的人,都应该知道,C++语言中的构造函数,析构函数,拷贝构造函数,赋值运算符重载函数,如果不定义,编译器会自动生成的,当然,生成的只是一些最基本的,在达不到我们要求的条件下,就需要我们自己重新定义这些函数。

我们现在说的讲的是深拷贝与浅拷贝,当然讨论这个问题的基础,一般情况下是我们定义的变量是以指针形式出现的,原因就在于,不论赋值还是拷贝,我们要实现两个指针指向的内容一致,那我得到新的指针和原指针是指向同一块内存空间还是两块内存空间的相同内容。如果是指向同一块空间,就存在了安全隐患,我们在自己管理空间时,就很有可能对一块空间进行了多次的释放,有些编译器下会报错,甚至直接奔溃,有些编译器虽不会抛出异常,但也会对后续的程序造成未知的错误。

那么,现在就以String为例,看看如何解决这些问题。

//参数列表中,pstr为char* 类型,s为String类型

//实现方法1:

classString{friendostream&operator<<(ostream&_out,constString&s);public:String(constchar*pstr):_str(newchar[strlen(pstr)+1]){strcpy(_str,pstr);cout<<"构造"<<endl;//做标识}String(constString&s):_str(newchar[strlen(s._str)+1]){strcpy(_str,s._str);cout<<"拷贝构造"<<endl;//做标识}String&operator=(constString&s){if(this==&s)//不给自己赋值,防止对一块空间进行二次析构{char*tmp=(newchar[strlen(s._str)+1]);strcpy(tmp,s._str);delete[]_str;_str=tmp;}cout<<"赋值重载"<<endl;//做标识return*this;//注意返回值}~String(){if(this!=NULL){delete[]_str;_str=NULL;}cout<<"析构"<<endl;//做标识}private:char*_str;};//输出运算符重载ostream&operator<<(ostream&_out,constString&s){_out<<s._str<<endl;return_out;}

//*****************************************************************************************

//String类的实现2

classString{friendostream&operator<<(ostream&_out,constString&s);public:String(constchar*str):_str(newchar[strlen(str)+1])//同上{strcpy(_str,str);}//拷贝构造String(constString&s):_str(NULL){Stringtmp(s._str);std::swap(_str,tmp._str);}//赋值运算符重载//String&operator=(constString&s)//{//if(this!=&s)//{//char*tmp(s._str);//用s._str或者s实例化tmp都可以//std::swap(_str,tmp);//}//return*this;//}//赋值运算符重载之开辟空间法String&operator=(constString&s){if(this!=&s){char*tmp=newchar[strlen(s._str)+1];strcpy(tmp,s._str);delete[]_str;_str=tmp;}return*this;}//析构~String(){if(NULL==_str){delete[]_str;_str=NULL;}}private:char*_str;};//输出运算符重载ostream&operator<<(ostream&_out,constString&s){_out<<s._str<<endl;return_out;}

// String类的实现3------>浅拷贝实现防止内存的多次释放

classString{friendostream&operator<<(ostream&_out,constString&s);public:String(constchar*pdata):_str(newchar[strlen(pdata)+1]),_count(newint){strcpy(_str,pdata);*_count=1;}String(constString&s):_str(s._str),_count(s._count){_count++;}String&operator=(constString&s){if(this!=&s){if(--(*_count)==0){delete[]_str;delete_count;}_count=s._count;_str=s._str;_count++;}return*this;}~String(){if(--(*_count)==0){delete[]_str;delete_count;}}private:char*_str;int*_count;};//输出运算符重载ostream&operator<<(ostream&_out,constString&s){_out<<s._str<<endl;return_out;}

//*****************************************************************************************

友元函数受第一参数的限制,只能采用类外定义,引入友元

方法三,关于引入计数器,在面试过程中,这是最不推荐的方法,HR往往更倾向于让你写出深拷贝的方法。

深拷贝与浅拷贝是面试过程中经常出现的题目,弄清楚这类问题是非常必要的