
- 构造函数
- 有参构造函数
- 无参构造函数
- 简略版本
- 深拷贝和浅拷贝
- 赋值重载
- 析构函数
- npos
- c_str
- 迭代器
- reserve
- push_back() && append()
- []运算符
- insert
- erase
- +=
- find
- cout,cin
- 总结:
- string.h 和测试代码
在前面我们学习string的功能,今天我们来模拟一下string类的实现。
构造函数 有参构造函数string(const char *str)//(1)
:_size(strlen(str)),//(2)
_capacity(_size)//(3)
{
_str = new char[_capacity + 1];//(4)
strcpy(_str, str);//(5)
}
(
1
)
(1)
(1)形参传递的字符串属于常量区,不能修改,const不能忘了
(
2
)
(2)
(2)计算字符串的长度
(
3
)
(3)
(3)初始化字符串容量_capacity
(
4
)
(4)
(4)为字符指针开辟空间,这里需要多开一个字节,因为传进来的可能是个空串,空串含有一个'/0'(strlen计算到即停止,不含()。string
------------------------------------------------------------我是分割线💥💥💥💥💥💥💥💥💥💥-----------------------------------------------------------
无参构造函数 ):_size
(0),//(1)_capacity(
0),//(2)_str(
char[new 1])//(3)[0
{
_str]=';' }
(
1
)
(
2
)
(1)(2)
(
1)(2)_size_capacity
(
3
)
(3)
因为传进来的是一个空串,所以和(都设置为0
3)/0string(空串有个const,为其开一个字节空间。
为了简略,上面的两种构造函数可以合成一个:
char*= "")str//传进来的可能是空串 这里包含了无参和有参:_str(
),_sizenullptr(0
),_capacity(0
)int=strlen
{
( newcapacity ) ;//(1)str=char[
_str + new 1]newcapacity ; //(2)strcpy(,
);_str//(3) str=;//(4)
_size = newcapacity;//(5)
_capacity } newcapacity
(
1
)
(1)
(
1)
(
2
)
(2)
(计算形参字符串的长度
2)
(
3
)
(3)
(申请空间
3)
(
4
)
(4)
(拷贝字符串的数据
4)_size
(
5
)
(5)
更新(
5)_capacity拷贝构造函数的传统写法:自己开空间,完成深拷贝string更新(
------------------------------------------------------------我是分割线💥💥💥💥💥💥💥💥💥💥-----------------------------------------------------------
在模拟拷贝构造函数之前,我们首先学习一下深拷贝和浅拷贝。
浅拷贝:计算机默认提供的拷贝构造函数和赋值重载函数实现的都是浅拷贝,浅拷贝完成的字节序的拷贝。举例说明:浅拷贝就是抄作业,连名字也一起照抄的一种行为。
这种不修改的名字的抄作业行为有时候就容易被老师发现,然后被逮住。
在计算机中也是如此:
浅拷贝带来的问题就是总结就是:堆区申请的内存被重复释放
浅拷贝的问题需要通过人为深拷贝进行解决。
解决方法如下:
在了解了深浅拷贝以后,我们继续学习拷贝构造函数的实现:
const
&)//拷贝构造 string :s_size(
.)//(1)s_capacity_size(.
),s//(2)_capacity_str()
//reserve(_capacity); !!!!拷贝构造这里不能使用reserve ,因为strcpy会解引用空指针=nullptrchar
{
[
_str + new 1]_capacity;//(3)strcpy(,
.)_str; s//(4)_str}reserve_str
strcpy
注意:这里的拷贝构造不能用new开空间,指针
(
1
)
(
2
)
(1)(2)
是一个空指针,而需要传入空指针,系统会报错,所以需要通过(申请空间。
1)(2)_size_capacity
(
3
)
(3)
拷贝和(。
3)'
(
4
)
(4)
'(进行深拷贝,在堆区重新申请一块空间,字符串末尾有个4所以需要多开一个空间。
)拷贝构造函数的现代写法:复用string的有参构造函数voidswap(将数据拷贝到新空间。
&
) ::swapstring (s,
{
std.);_str:: sswap_str(,
std.);_size:: sswap_size(,
std.);_capacity} sstring_capacity(const
&
):_size string (s0
),_capacity(0)
,_str()tmp
(.nullptr)
{
string ;//复用有参构造函数sswap_str();
}赋值重载的传统写法:老老实实进行开空间,深拷贝tmp&=
(
------------------------------------------------------------我是分割线💥💥💥💥💥💥💥💥💥💥-----------------------------------------------------------
赋值重载&
string) operatorif(string !=s& {
) //(1)thischar*s=char
{
[ .temp + new 1]s;_capacity //(2) strcpy(,.
);temp//(3) s[_str];//(4)
delete =._str;//(5)
_size = s._size;//(6)
_capacity = s;_capacity//(7)}
_str return temp*;
}
(
1
)
(1)
this(
1
)s1 = s1
(
2
)
(2)
(赋值重载的时候,可能会有这样一种情况2,对于这种自己给自己赋值的情况,直接进行返回。
)
(
3
)
(3)
(3 在进行深拷贝的时候,先进行申请空间,因为申请空间可能会失败。
)
(
4
)
(4)
(4将数据拷贝到临时对象中。
)
(
5
)
(5)
(5赋值重载对象可能先前就指向了一块空间,需要将这块空间进行释放。
)_size_capacity
(
6
)
(6)
拷贝临时对象的(和6
)_str赋值重载的现代写法:复用拷贝构造函数voidswap将(指针指向临时对象中申请的空间
------------------------------------------------------------我是分割线💥💥💥💥💥💥💥💥💥💥-----------------------------------------------------------
&
) ::swapstring (s,
{
std.);_str:: sswap_str(,
std.);_size:: sswap_size(,
std.);_capacity} s&_capacity=(
)
string//(1) operatorif(string s!=&
{
) swapthis ( )s;
{
//(2)}sreturn*;
}
(
1
)
(1)
this(
1
)
(
2
)
(2)
(2:赋值重载运算符的现代写法精髓正是在这,因为形参是实参的拷贝,所以这里会先调用拷贝构造函数完成深拷贝。
)s1=s1~string(:防止)这种自己给自己赋值的情况,直接将拷贝构造得到的对象和该对象交换。
[];=
{
delete;=_str=
_str 0 nullptr;
_size } _capacity const char*
c_str
析构函数的实现很简单,释放空间就好。
------------------------------------------------------------我是分割线💥💥💥💥💥💥💥💥💥💥-----------------------------------------------------------
nposc_strstring::npos是一个静态成员常量,表示size_t的最大值(Maximum value for size_t)。在使用中通常将其定义为-1。
( )const return;//(1) }
{
(
1
)
(1)
_str(
1
)typedefchar*;返回字符指针。
迭代器 //(1) typedefconst iteratorchar*
; //(2) begin( const_iterator)//(3)
iterator return;} {end
( _str)
//(4)
iterator return+;}
{
begin _str ( _size)
const
const_iterator return;} end
{
( _str)
const
const_iterator return+; }
{
(
1
)
(
2
)
(1)(2)
_str _size(
1
)(2)普通迭代器const迭代器typedef
(
3
)
(3)
迭代器又分为和(,这里对两个返回值进行3
)
(
4
)
(4)
(4返回字符的第一个位置
)voidreserve(int返回最后一个字符的下一个位置
------------------------------------------------------------我是分割线💥💥💥💥💥💥💥💥💥💥-----------------------------------------------------------
reserve) char*= newcapacitychar
{
[ +tmp 1 new ];newcapacity //(1) strcpy(,)
;//(2)tmp[ _str];//(3)
delete =;_str//(4)=
_str ; tmp//(5)}
_capacity
(
1
)
(1)
newcapacity(
1
)
(
2
)
(2)
(2申请新空间。
)
(
3
)
(3)
(3将旧空间的数据拷贝到新空间。
)
(
4
)
(4)
(4将旧空间的数据释放。
)
(
5
)
(5)
(5让指针指向新空间。
)_capacity
(
1
)
(1)
(更新1。
)push_back()voidpush_back(char
) if(== ch)
{
//(1) reserve_size ( _capacity==0
{
?4_capacity : * 2 ) ; _capacity //(2) }[++]
=
_str;_size//(3)[ ] ch=';'
_str//(4)_size}
(
1
)
(1)
(1
)
(
1
)
(1)
(1)说明空间用完了,需要扩容
042倍
(
1
)
(1)
如果原空间为(,就扩容为1,反之扩大)
(
1
)
(1)
(1)尾插字符
'
(
1
)
(1)
'(1)别忘了append()
voidappend(constchar*
) int=strlen ( )str;
{
//(1) len int =+str;//(2)if
( newcapacity ) len //(3) _sizereserve(
+ 1newcapacity >= _capacity);
{
}memcpynewcapacity ( +,,
)
;//(4)_str = _size; str//(5) len=;//(6)
_size [ newcapacity]=
_capacity ';' newcapacity //(7)}
_str
(
1
)
(1)
_size ( 1)
(
2
)
(2)
(2)
(
3
)
(3)
计算要插入的字符串的长度。
(3)
(
4
)
(4)
计算当前所需要的空间容量。
(4)
(
5
)
(
6
)
(5)(6)
当前容量如果不够,就进行扩容。
(5)(6将字符串插入。
)_size_capacity
(
7
)
(7)
(7)更新'
(
1
)
(1)
'和。
(1)普通版本char别忘了末尾还有个&
------------------------------------------------------------我是分割线💥💥💥💥💥💥💥💥💥💥-----------------------------------------------------------
[]运算符[](int)assert
(< operator);return[ pos]
{
;}pos
(
1
)
(1)
_size(
1 _str)posconst版本const
char
&[](int)
const assert( operator<);return pos[]
{
;}pos 引用 _size[]const
const _str
(
1
)
(1)
pos(
1
ps::这里返回的时候别忘了+),insert插入字符需要支持读写 *** 作
两个版本的实现基本相同,void版本返回值是insert的,只能读但是不能写。
------------------------------------------------------------我是分割线💥💥💥💥💥💥💥💥💥💥-----------------------------------------------------------
(int,char)assert
( <=); posif( ch==
{
)reservepos ( _size==0
? 4_size : _capacity*
2)_capacity ; //(1) int = ; _capacity int =;while(
< l ) pos//(2)
[ r ] _size=
[ -l 1 r];
{
_str--r; } _str[r ] =;//(3)
r[++
]
_str=pos';' //(4) ch}
(
1
)
(1)
_str(_size1 )
(
2
)
(2)
(
2
)
(
3
)
(3)
(3如果容量不够,就进行扩容。
)
(
4
)
(4)
(4插入字符需要挪动数据,从最后一个位置开始挪动。
)_size
(
2
)
(2)
(将要插入的位置赋值。
2)insert插入字符串&insert更新(,并且末尾添上int。
,constchar*)//插入字符串。
string//判断容量够不够 int=strlen pos( ) ; //(1)strif(
{
+
) len //(2) reserve(str+);
int =len ; _size > _capacityint=
+;len while _size(+
- l 1 pos<
) r //(3) _size [ len]
= [l-len]; -- r;}
{
_strstrncpyr( + _str,r , len);
r//(4)+=
;
//(5)return_str * pos; str} len
(
1
)
(1)
(
_size 1 len)
(
2
)
(2)
(this2
)
(
3
)
(3)
(3)计算要插入的字符串的长度。
(
4
)
(4)
(4)判断是否需要扩容。
(
5
)
(5)
(5)挪动数据。
_size&erase(int将要插入的字符串插入。
=0,int=更新)。
------------------------------------------------------------我是分割线💥💥💥💥💥💥💥💥💥💥-----------------------------------------------------------
erasestringassert (<) pos ; if( == len || npos+
{
)//(1)pos [ _size]=
';' =len ; npos } poselselen >= _sizestrcpy(
{
_str+pos, + +)
_size ; pos//(2)
-=
;
{
}return_str * pos; _str } pos
(
1
)
(1)
len(1
_size ) lenpos
(
2
)
(2)
(this2
)
(
1
)
(1)
(1):判断是否需要删除+=字符串位置开始的所有字符。
&+=(constchar,将数据拷贝到被删除的位置。这里我们进行画图理解。
*)append();
string//(1) operatorreturn*; }
(
1
)
(1)
str
{
(1str)
(
1
)
(1)
( 1this)
+=字符
&+=(char)复用append函数。
push_back();//(1)return
string* operator;}
(
1
)
(1)
ch
{
(1ch)
(
1
)
(1)
( 1this)
int
find(char,int复用push_back函数。
------------------------------------------------------------我是分割线💥💥💥💥💥💥💥💥💥💥-----------------------------------------------------------
find=0)for(查找字符第一次出现的位置
int =;< ch;++ pos)//(1)if
{
( [] i == pos) i return _size; i}return-
{
1 ;_str}i
(
1
)
(1)
ch(
1 i)
(
2
)
(2)
(2)
-1
(
2
)
(2)
(2)对字符串遍历一遍,如果找到了就返回该字符对应位置
intfind(constchar没找到就返回*。
,int=0)查找字符串第一次出现的位置
const char*= strstr( s+ , pos ) ;//(1)
{
//出现的位置,没找到返回空指针。 if( ptr == )return_str ; pos} selsereturn-
;
//(2) }ptr } nullptr
(
1
)
(1)
{
npos(
1
)
{
(
2
)
(2)
ptr _str(2
)
cout
&<<(&,使用strstr库函数进行查找字串,如果没找到,返回-1
&)//cout << s.c_str() << endl;//不能这样写 因为cout判断结束是遇到'//就会导致后面的字符打印不出来',但是如果字符串中插入'for',(int这里涉及指针-指针,我们进行画图理解:
=
ostream0 operator;<ostream.cout; string ++s)
{
<<
[
] ;return i ; }cin i & s(_size& i,&
cout ) s.iclear(
) cout;
//(1)
char
istream= operator>>.istreamget in( string) s;
{
swhile(!=' '&&!=
'\n' ch ) in+=;=.get
( )ch ; //(2) } ch return ;}
{
s
(
1
)
(1)
ch
ch ( in1)
(
2
)
(2)
(2
)
(
1
)
(1)
in
(
1)
(
2
)
(2)
(在输入字符串之前必须先clear一次,字符串在先前可能有字符存在
2)
(
3
)
(3)
(cin.get(),每次读取一个字符。
3)
(
4
)
(4)
(:使用strcpy函数时要注意实参是不是一个可以使用的地址,并且不能为空。
4)‘
(
5
)
(5)
’(:临时对象的生命周期到函数结束,接着会被析构掉。
5)const
(
6
)
(6)
:指针-指针得到的是两个指针的间隔长度。
如:
(6) ( 7 ) (7) :reserve每次都会多开一个空间,用来存储(
7)#pragmaonce:字符串属于常量区,形参接收的时候需要加#
include#include;#:重载[]运算符的时候需要+引用,因为需要[]运算符需要支持读写 *** 作
include:typedefchar:insert,find,erase这里的对于库函数的用法很灵活,需要多练习。
*; typedef
constchar
*;
using namespace std//const 迭代器就是字符串的内容只能读不能写
begin()
namespace m_string {
class string {
publicreturn
; } end iterator(
) return +; const_iterator//因为end指向所以数据的下一个位置,所以直接+size就好了}
iterator begin()
{
const _str//const迭代器const对象进行调用,后面的const修饰的是this指针,也就是类的成员不能修改
return
iterator ;}end
{
( _str ) _sizeconstreturn
+
const_iterator ;}string(const
{
char _str*
=
const_iterator "")//传进来的可能是空串 这里包含了无参和有参:
{
_str _str ( _size)
,
_size(0 ),str_capacity(0)
int=strlennullptr()
;=char[+
1];strcpy
{
( newcapacity , );str=;
_str = new ;}newcapacity char *c_str(
)return_str; str}int
_size capacity newcapacity(
_capacity ) newcapacityreturn
;
}int size()
{
return _str;
}
void reserve(int
{
) _capacitychar
*
= char[+
{
1 _size]
;
strcpy (,) newcapacity;
{
[ ]tmp ; new =;newcapacity = ;}void
push_back(tmpchar _str)//尾插字符
delete //需要判断是否需要扩容if_str(
_str == tmp)
_capacity reserve newcapacity(
==
0 ?4: ch*2
{
)
; }_size [ _capacity++
{
]=_capacity ; [ ] = ';' _capacity } ~string(
)
_str[_size]; = ch=
_str0_size; } voidswap
(
&)::swap
{
delete (,_str.
_size ) _capacity ; ::swap
(
, .)string ;s::
{
stdswap(,_str. s)_str;}
std//传统写法!!!!!!!//string(const string &s)//拷贝构造// :_size(s._size),_size// _capacity(s._capacity), s// _str(nullptr)_size// //reserve(_capacity); !!!!拷贝构造这里不能使用reserve ,因为strcpy会解引用空指针// _str = new char[_capacity+1];
std// strcpy(_str, s._str);//}//现代写法_capacitystring s(_capacityconst&
)
:
_size
(
0
)
//{
,
_capacity
(
0
)
,_str( string )stmp
(.);//复用有参构造函数swap
();}//-----------------------------------------------------------------
//operator=传统写法// if (this != &s)//(1)nullptr// char *temp = new char[s._capacity + 1];//(2)
{
string // strcpy(temp, s._str);//(3)// delete[]_str;//(4)s// _size = s._size;//(5)_str// _capacity = s._capacity;//(6)// _str = temp;//(7)// }
// return *this;//}tmp&=
(
)
if
//string& operator=(string &s) {
(
// {
!=
&
)
swap
(
)
;
}
return
string* operator;}string svoid
{
resize (this int ,schar
{
=')'s//开的空间大于原空间if
(
) reservethis(
)
; memset(+ newcapacity,, ch-);
{
=
; }newcapacity >= _capacityelse
{
if(newcapacity<)
[]_str = _size';' ch= newcapacity ; _size}}
_capacity char newcapacity[
]
( int )newcapacity assert _capacity(
{
_str<newcapacity) ; return[
_size ] newcapacity;
}
const
char operator&[]( xint
{
)constx assert _size(<
) _str;xreturn[
]
; }void operatorinsert(int, xchar)
{
assert(x <= _size);
if _str(x==)
reserve
( ==0? pos4: ch*
{
2)pos ; _sizeint=
; int_size = _capacity;
while(_capacity < ) [ ] = _capacity [ -1]
; l -- pos;
} r [ _size]
= ;l [ r++
{
_str]r= ';' _str}r & insert(int
r,const
char
_str*pos) //插入字符串 ch//判断容量够不够
_strint=_sizestrlen ( );
if
string( +)reserve pos( + ) ;strint=
{
;
int len = +;strwhile(
+ -len 1 _size > _capacity<
)[len ] _size=[
- l ] pos;
-- r ; _size } len<<
<< ;lstrncpylen(+ , r,
{
_str)r; += _str;r return len*;
r}int
find
cout ( _str char endl,
int=_str 0 pos) strfor len(int
_size = len;
< ;this++
)
if ([] ch==) posreturn;}
{
return -1 i ; pos} i int _sizefind i(const
{
char *_str,iint = ch0
) iconst
char
* =strstr(
+
, );//找到了就返回子串在主串中第一次 //出现的位置,没找到返回空指针。if s( == pos ) return;
{
} elsereturn ptr - ;}_str } pos& s+=(char
)
if (ptr == nullptr)
{
reserve npos(
==
0
{
? ptr 4 _str:
*
2
string )operator;push_back( ch)
{
; return_size * _capacity;
}char_capacity * ; int ; int _capacity ; staticconstsize_t
=-ch1;
void appendthis(
const
char *_str)
int _size=
strlen _capacity(
) ; int npos = +;if
( )reserve( + 1str)
{
; len } memcpy(str+,
, newcapacity ) len ; _size=
; [newcapacity >= _capacity]
{
=';'newcapacity = ;}&
erase
(int_str = _size0 str, lenint=
_size ) newcapacityassert
_str(_size< ) ;if
_capacity ( newcapacity ==
||
string+ )[] pos = ';'= ; len } nposelse
{
strcpy(pos + _size,+
+ )len ; npos << pos ( len >= _size+
{
_str)pos<< ; <<(
_size + pos+
)
<<
{
;-=_str ; pos} _str return pos * len;}
cout void clear_str ( pos) [ endl0
cout ] =_str ';' pos = len0 ; endl}
_size } len;
&
<< (this&
,
& )//cout << s.c_str() << endl;//不能这样写 因为cout判断结束是遇到'//就会导致后面的字符打印不出来',但是如果字符串中插入'for',(
{
_strint=0 ; <.
_size ; ++)
<<
[]
ostream; operatorreturn;ostream}cout& string (s&
{
,
&
) .clear i ( ); i char s=_size. iget(
cout ) s;iwhile(
!= cout' '
&&
istream!= operator>>'\n'istream) in+= string; s=
{
s.get();
} ch return in;}voidtest1(
) //测试有参和无参 ok!ch //测试无参 /*string s1;
cout << s1.c_str() << endl;
cout << s1.capacity() << endl;
cout << s1.size() << endl;*/ //测试有参 ch /* string s2("hello");
cout << s2.c_str() << endl;
cout << s2.capacity() << endl;
cout << s2.size() << endl;*/ //测试有参空串/*string s3("");
cout << s3.c_str() << endl;
cout << s3.capacity() << endl;
cout << s3.size() << endl;*/
{
s } chvoid
ch test2 in()//测试迭代器//测试普通迭代器+无参/*string s1;
string::iterator it = s1.begin();
while (it!=s1.end())
{
cout << *it<<" ";
it++;
}*/
//测试普通迭代器+有参
/*string s2("helloddddddddddddd");
string::iterator it = s2.begin();
while (it != s2.end())
{
cout << *it << " ";
it++;
}*/ in//测试const迭代器+
/*const string s2("helloc");
string::const_iterator it = s2.begin();
while (it != s2.end())
{
cout << *it << " ";
it++;
}*/
} voidtest3()
{
//测试push_Back 和reserve
//测试能否正常扩容和插入
/*string s1;
s1.push_back(1);
s1.push_back(2);
s1.push_back(3);
s1.push_back(4);
cout << s1.size() << endl;
cout << s1.capacity() << endl;*/
//前4个容量为4,插入第五个以后容量变为8
/* s1.push_back(5);
cout << s1.size() << endl;
cout << s1.capacity() << endl;*/
//测试能否搭配迭代器进行使用
/*string s2("h");
s2.push_back('e');
s2.push_back('l');
s2.push_back('l');
s2.push_back('o');
for (auto ch : s2)
cout << ch;*/
} voidtest4()
{
//测试拷贝构造
s1
(
"hello"
)
;
s2
( );for(
{
auto
:
)
<<
;
}
void
test5 ()//测试赋值重置运算符s1
{
string ("hello");s2
string ("hellooooo"s1);
= ;<< ch . s2size
cout ( ch)
<<
; <<.capacity(
{
string )<<;}void
string test6()//测试resize//string s1("aaaaa");//原空间大于要申请的空间
s2 //s1.resize(1); s1//for (auto ch : s1)
cout // cout << ch; s2s2("aaaa") ; endl//原空间小于要申请的空间
cout . s2resize(10) ; endlfor
(
auto :)<<;
{
<<
.
capacity
(
string )<<;}voidtest7
s2()//测试[]s1("hello"
) ;<< ch [ s20
cout ] ch<<
cout ; s2<<[1] << endl;
<<
[ 2]<<;
{
string <<[3]<<
cout ; s1<<[4 ] endl<<
cout ; s1<<[5 ] endl<<
cout ; s1//越界,断言程序崩溃}void test8 endl(
cout ) s1//+=;+= 'a' endl;
cout << s1.c_str( ) endl<<
cout ; s1}voidtest9 ( endl)//append
s1
( "aaa");.
{
string s1append
s1 ( "h")
cout ; s1<<.c_str( ) endl<<
;
} voidtest10()
{
string //cout 和cins1("hello dasdasd")
s1;;<<<<;}
cout void s1test11()//insert s1 endl(
"hello"
) ;.insert(
{
string 1,"adc");
cin >> s1<<
cout . s1 c_str endl(
)
<< ;}voidtest12
{
string ()//find//查找单个字符s1
s1("hello");<< .find(
cout "llo" s1);//查找字符串} void endltest13
(
) //erases1("hello"
{
)
string ;.erase(2
cout , s12);<<.c_str
(
)
<< ;}voidtest14
{
string ()//测试现代写法的拷贝构造s1(
s1"hello");s2();<<
cout << s1;<<.size ( endl)
<<
; <<.capacity(
{
string )<<;}void
string test15(s1)//测试operator现代写法
cout s1 s2 ( endl"dasd"
cout ) s2;=;<< << endl;
cout << s2.capacity() << endl;
<<
. size()<<
{
string ;}}
string s2s1
cout s2 endl
cout s2 endl
cout s1 endl
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)