已知类String的原型为:
class String
{
public:
String(const char *str=null);//构造函数
String(const String &other);//拷贝构造函数
~String(void);//析构函数
String& operate =(const String &other);//赋值函数
private:
char * m_data;//用于保存字符串
};
1.构造函数
String:String(const char* str=null)
{
if(str==null)//str需要判断是否为null
{
m_data=new char[1];
m_data[0]='\0';
}
else
{
int length = strlen(str);
m_data = new char[length+1];
strcpy(m_data,str);
}
}
2.析构函数
String::~String(void)
{
delete [] m_data;//由于m_data是内部数据类型,也可以写成delete m_data;
}
3.拷贝构造函数
所有需要分配系统资源的用户定义类型需要一个拷贝构造函数,这样我们可以使用如下声明:
Mystring s1("hello");
Mystring s2 = s1;
拷贝构造函数可以在函数调用中以传值方式传递一个Mystring参数,并且在当一个函数以值的形式返回Mystring对象时实现“返回时复制”
String::String(const String &other)
{
if(other.m_data==null)//此处最好加null判断
{
m_data = new char[1];
*m_data = '\0';
}
else
{
int length = strlen(m_data);
m_data = new char[length+1];
strcpy(m_data, other.m_data);
}
}
4.赋值函数
赋值函数可以实现字符串的传值活动:
MyString s1("hello");
MyString s2;
s1=s2;
代码如下:
String& String::operator =(const String &other)
{
if(this == &other)//检查自赋值
return *this;
delete [] m_data;//释放原有的内存资源
if(other.m_data==null)
{
m_data = new char[1];
*m_data = '\0';
}
else//分配新的内存资源,并赋值内容
{
int length = strlen(m_data);
m_data = new char[length+1];
strcpy(m_data, other.m_data);
}
return *this;//返回本对象的引用
}
如果再这个类型中添加新的指针成员变量,我们至少需要做两处修改,即同时在析构函数和这个赋值函数里添加一条delete语句来释放新指针所指向的内存,通常我们会记得在析构函数里用delete释放指针成员变量,但未必每次都记得到赋值运算符函数来添加代码释放内存。
于是我们采用下述方法:
String& String::operator =(const String &other)
{
if(this != &other)
{
String strTemp(other);
char *PTemp = strTemp.m_data;
strTemp.m_data = m_data;
m_data = PTemp;
}
return *this;//返回本对象的引用
}
在这个函数中,定义一个临时变量strTemp,并把strTemp的m_data指向当前实例(*this)的m_data。由于strTemp是个局部变量,程序运行到if语句外面时也就出了该变量的域,就会自动调用strTemp的析构函数,就会把strTemp.m_data所指向的内存释放掉,由于strTemp.m_data指向的内存就是当前实例之前的m_data的内存,这就相当于自动调用析构函数释放当前实例的内存。如果新增加指针成员变量,我们只需要在析构函数里正确的释放,而不需要对赋值运算符做任何修改。