一个类里面有6个默认成员函数:构造函数,拷贝构造函数,赋值操作符重载函数,析构函数,取地址操作符重载函数和const修饰的取地址操作符重载函数。
传统写法的String类:里面只有简单的默认构造函数,拷贝构造函数,赋值操作符重载函数和析构函数。
class String
{
public:
//构造函数
String(const char *str="")
{
//构造string类对象时,如果传递nullptr指针,认为程序非法。
if (str == nullptr)
{
assert(false);
return;
}
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
//拷贝构造函数
String(const String &s)
:_str(new char[strlen(s._str)+1])
{
strcpy(_str, s._str);
}
//运算符重载函数
//先开辟一个新的空间,然后在将原来的值拷贝到新的里面,然后释放原来的那个
//新开辟的空间大小不一定和原来空间大小一样,如果不拷贝会出现数据丢失
//释放原来的指针,将最开始的那个指针指向我们最后开辟的地址
String& operator=(const String &s)
{
//这里判断一下是否自己给自己拷贝,不相等才进行拷贝相等就直接返回。
if (this != &s)//判断的是地址
{
char *pstr = new char[strlen(s._str) + 1];
strcpy(pstr,s._str);
delete[] _str;
_str = pstr;
}
return *this;
}
//析构函数
//判断一下_str是否存在
~String()
{
if (_str)
{
delete[] _str;
_str = nullptr;
}
}
private:
char *_str;
};
现代写法的String类:里面只有简单的默认构造函数,拷贝构造函数,赋值操作符重载函数和析构函数。
class String
{
public:
//构造函数
//先判断一下str是否为空,如果为空就重新给它一个指针空值
String(const char *str = "")
{
if (nullptr == str)
{
str = "";
}
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
//拷贝构造函数
String(const String &s)
:_str(nullptr)
{
//用对象调用构造函数
String strTmp(s);
swap(_str,strTmp._str);
}
//操作符重载函数1
String& operator=(const String &s)
{
if (this != &s)
{
String strTmp(s);
swap(_str, strTmp._str);
}
return *this;
}
//操作符重载函数2
String& operator=(String s)
{
swap(_str, s._str);
return *this;
}
//这两个操作符重载函数第一个是函数内生成拷贝构造,第二个是传参时生成拷贝构造。
~String()
{
if (_str)
{
delete[] _str;
_str = nullptr;
}
}
private:
char *_str;
};
两种写法的比较:
一、构造函数:基本一样
二、拷贝构造函数:现代写法可以完成代码的复用,其比较简洁。优点:自己不用申请空间,不拷贝内容。通过调用构造函数(申请空间,拷贝类容)生成一个新的临时对象。直接获取临时对象的全部内容(通过交换指针完成)完成当前拷贝构造。
三、赋值操作符重载函数:现代写法可以完成代码的复用,其比较简洁。优点:自己不用申请空间,不拷贝内容。通过调用构造函数(申请空间,拷贝类容)生成一个新的临时对象。直接获取临时对象的全部内容(通过交换指针完成)完成当前拷贝构造。
四、析构函数:基本一样。