当类的成员对象不包含指针类型时,拷贝构造和赋值运算符重载采用浅拷贝不写即默认采取值拷贝的形式。
若类的成员对象为指针类型时,若不自定义**“拷贝构造”和“赋值运算符重载”**会出现一种情况即指针悬挂,如下情况:
浅拷贝:
简单的赋值浅拷贝
String s1("himark");
Stirng s2=s1;
S1和S2包含的指针对象同时指向一块内存
析构时delete会析构两次这个内存块,导致程序崩溃
深拷贝:
String s1("himark");
Stirng s2=s1;
构造S2时拷贝一块与S1数据块一样大的内存,并将值拷贝下来
使得S1,S2指向自己的数据块,析构时各自释放自己的数据块
自主实现String类
#pragma once
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
class String
{
//输出运算符重载的友元函数
friend ostream& operator<<(ostream& _cout, const String& s);
//输入运算符重载的友元函数
friend istream& operator>>(istream& _cin , String& s);
public:
//构造函数
String(const char* str)
:_str(new char[strlen(str)+1])
, _size(strlen(str))
, _capacity(strlen(str)+1)
{
strcpy(_str, str); // '\0‘也拷贝了
}
//拷贝构造函数 String s2(s1)
String(const String& s)
//深拷贝
:_str(new char[strlen(s._str)+1])
, _size(strlen(s._str))
, _capacity(strlen(s._str)+1)
{
_str=s._str;
_size=s._size;
_capacity=s._capacity;
}
//析构函数
~String()
{
if(_str)
{
delete[] _str; //动态释放空间
_str = NULL;
}
}
const char* c_str()
{
return _str;
}
//增删改查
void Expand(size_t n);
void PushBack(char ch);
void PushBack(const char* str);
void PopBack();
void Insert(size_t pos, char ch);
void Insert(size_t pos, const char* str);
void Erase(size_t pos, size_t n);
size_t Find(char ch) const ;
size_t Find(const char* str)const;
void Swap(String& s);
//操作符重载
//s1=s2
String& operator=(String s);
//s1 + 'a' 传值返回
String operator+(char ch);
//s1 += 'a' 传引用返回
String& operator+=(char ch);
//s1 + "str" 传值返回
String operator+(const char* str)
//s1 += "str" 传引用返回
String& operator+=(const char* str);
bool operator<(const String& s) const ;
bool operator<=(const String& s) const ;
bool operator>(const String& s) const ;
bool operator>=(const String& s) const ;
bool operator==(const String& s) const ;
bool operator!=(const String& s) const ;
private:
char* _str; //保存字符串
size_t size; //大小
size_t _capacity; //有效长度
};
//输出运算符的重载
ostream& operator<<(ostream& _cout, const String& s)
{
_cout<<"str: "<<s._str<<" size:"<<s._size<<" capacity:"<<s._capacity<<endl;
return _cout;
}
//输入运算符的重载
istream& operator>>(istream& _cin, String& s)
{
_cin>>s._str;
return _cin;
}
//函数实现
#include"string.h"
#include<assert.h>
//扩容
void String::Expand(size_t n)
{
if(n>_capacity)
{
_str=(char*)realloc(_str, n+1);
_capacity=n+1;
}
}
//=========================================
//增删改查
void String::PushBack(char ch)
{
if(_size>=_capacity-1)
{
Expand(_capacity*2);
}
_str[_size]=ch;
_size++;
_str[_size]='\0';
}
void String::PushBack(const char* str)
{
sizez_t len=strlen(str);
if(len+_size>=_capacity-1)
{
Expand(len+size);
}
strcpy(_str+_size,str);
_size=strlen(_str);
}
void String::PopBack()
{
if(_size>0)
{
//将'\0'前移
_str[_size-1]=_str[_size];
--_size;
}
}
void String::Insert(size_t pos, char ch)
{
if(_size>=_capacity)
{
Expand(_capacity*2);
}
size_t end=_size;
while(end>=pos)
{
_str[end+1]=_str[end];
--end;
}
_str[pos]=ch;
++_size;
}
void String::Insert(size_t pos, const char* str)
{
size_t len=strlen(str);
size_t tmp=len;
if(_size+len>_capacity)
{
Expand(_size+len);
}
size_t end=_size;
while(end>=pos)
{
_str[end+len]=_str[end];
--end;
}
while(len-- >0)
{
_str[pos++]= *str++;
}
_size+=tmp;
}
void String::Erase(size_t pos, size_t n)
{
if(pos+n>=_size-1)
{
_str[pos]='\0';
_size=pos;
}
else
{
strcpy(_str+pos, _str+pos+n); //直接将'\0'拷贝到pos处
_size-=n;
}
}
size_t String::Find(char ch) const
{
for(size_t i=0;i<_size;++i)
{
if(_str[i]==ch)
{
return i;
}
}
return -1;
}
size_t String::Find(const char* str) const
{
assert(str);
char* start=(char*)_str;
char* substart=(char*)str;
char*ret=(char*)_str;
while(*ret)
{
start=ret;
if(*start&&*substart&&(*start==*substart))
{
++start;
++substrat;
}
if(*substart=='\0')
{
return 1;
}
substart=(char*)str;
ret++;
}
return -1;
}
//s1.Swap(s2)
void String::Swap(String&s)
{
if(*this!=s)
{
swap(_str, s._str);
swap(_size,s._size);
swap(_capacity,s._capacity);
}
}
//s1=s2 现代写法
String& String::operator=(String s)
{
if(tihs!=&s)
{
_size=s._size;
_capacity=s._capacity;
swap(_str,s._str);
}
return *this;
}
String String::opreator+(const char* str)
{
string *s=new String;
s->_size=_size+strlen(str);
s->_capacity=_capacity+strlen(str);
s->_str=new char[s->_size+1];
strcpy(s->_str,_str);
strcat(s->_str,str);
return *s;
}
String& String::operator+=(const char* str)
{
_size+=strlen(str);
_capacity+=strlen(str);
char *s=new char[_size+1];
strcpy(s,_str);
strcat(s,str);
delete[]_str;
_str=s;
return *this;
}
bool String::operator<(const String& s) const
{
size_t i=0;
for(;i<_size&&i<s._size;++i)
{
if(_str[i]<s._str[i])
{
return true;
}
else
{
return false;
}
}
if(i==_size)
{
return true;
}
else
{
return false;
}
}
bool String::operator<=(const String& s) const
{
return *this<s||*this==s;
}
bool String::operator>(const String& s) const
{
return !(*this<=s);
}
bool String::operator>=(const String& s) const
{
return !(*this<s);
}
bool String::operator==(const String& s) const
{
size_t i=0;
for(;i<_size&&i<s._size;++i)
{
if(_str[i]!=s.str[i])
{
return false;
}
}
if(i==_size&&i==s._size)
{
return true;
}
return false;
}
bool String::operator!=(const String& s) const
{
return !(*this==s);
}
int main()
{
return 0;
}