string类有两种实现方式:
一:
class String
{
public:
String(char*pt = "")//使用缺省构造参数以满足无参对象和有参对象
{
if (NULL == pt)
{
p = new char[1];
*p = '\0';
}
else
{
p = new char[strlen(pt) + 1];
strcpy(p, pt);
}
}
~String()
{
if (NULL != p)//对p为NULL时候的处理,由此可见,可以释放NULL
{
delete[]p;
p = NULL;
}
}
String(const String&s)//拷贝构造参数
{
/*因为新定义的对象没有调用构造函数,所以在这里为p开辟一块空间*/
p = new char[strlen(s.p)+1];
strcpy(p, s.p);
}
String&operator=(const String&s)//赋值运算符重载
{
if (&s != this)//避免自己给自己赋值
{
/*创建一个新的指针变量pt的目的是避免new开辟空间失败的情况
下,赋值给原指针变量p,导致p的原值无法找到*/
char*pt = new char[strlen(s.p) + 1];
strcpy(pt, s.p);
delete[]p;//不释放的话内存泄漏
p = NULL;
p = pt;
}
return *this;
}
private:
char*p;
};
二.
构造函数和析构函数都和第一种一样(所以这里就不写了),不同的是拷贝构造函数和赋值运算符的重载
class String
{
public:
/*这里注意一定要初始化否则p没有合法的值,比如String s1=s2;s1.p就是一个野指针*/
String(const String&s) :p(NULL)
{
String temp(s.p);
std::swap(p, temp.p);
}
/*赋值运算符的重载一*/
String&operator=(const String&s)//详细解释见下图
{
if (&s != this)
{
String temp(s.p);
std::swap(p, temp.p);
}
return *this;
}
/*赋值运算符的重载二*/
String&operator=(String s)//参数不是引用,避免对象s被修改
{
std::swap(p, s.p);
return *this;
}
private:
char*p;
};
特别注意当在main ()函数中定义如下对象 String s1=s2;,编译器会进行优化处理,直接调用拷贝构造函数。