当类成员有指针数据成员的时候,应该重写复制构造函数、赋值操作符、析构函数。举例强加记忆,例子上网上搜寻后,有稍微的改动。
#include <iostream>
#include <assert.h>
using namespace std;
class String
{
public:
String( const char *str=NULL); //普通构造函数 空或者非空
String(const String &other); //复制构造函数
~String(void); //析构函数
String& operator=(const String& other); //赋值操作符
void showStr();
void foo(String s1){}; //说明复制构造函数隐式调用
private:
char* m_data;
};
/*************************************构造函数*************************************/
String::String(const char *str)
{
if (str==NULL)//当初始化串不存在的时候,为m_data申请一个空间存放'\0';
{
m_data=new char[1];
*m_data='\0';
}
else//当初始化串存在的时候,为m_data申请同样大小的空间存放该串;
{
int length=strlen(str);
m_data=new char[length+1];
strcpy(m_data,str);
}
}
/*************************************复制构造函数*************************************/
//也可初始化列表的时候分配m_data大小
//String::String(const String& other):m_data(new char[strlen.m_data+1])
//{strcpy(this->m_data,other.m_data);}
String::String(const String& other)
{
int length=strlen(other.m_data);
this->m_data=new char[length+1]; //再次分配资源,属于深拷贝
strcpy(this->m_data,other.m_data);
}
/*************************************赋值操作符*************************************/
String& String::operator=(const String& other)
{
if(this==&other)
return *this;
delete[] m_data;
m_data=NULL;//好习惯
int length=strlen(other.m_data);
m_data=new char[length+1];
if(m_data)
strcpy(this->m_data,other.m_data);
return *this;
}
/*************************************析构函数*************************************/
String::~String()
{
assert(m_data!=NULL);
delete [] m_data;
};
void String::showStr()
{
cout << this->m_data <<endl;
}
int main()
{
String s0; //调用构造函数
String s1("hello world");//调用构造函数
String s2(s0); //复制构造函数
String s3=s1; //复制构造函数
s2=s1; // 赋值操作符
s0.foo(s1); //复制构造函数,析构函数,foo函数 。
//产生临时对象(调用复制构造函数),临时堆像销毁(析构函数)
s1.showStr(); //hello world
s2.showStr(); //hello world
s3.showStr(); //hello world
}
①复制构造函数的形参必须为该类型的引用。若非引用,报错,(假如不报错,引起复制构造函数的无限递归),值传递,创建临时对象,调用复制构造函数,会一直无限下去。
②复制构造函数式资源再分配 B.m_data=new char[length+1], strcpy(m_data,A.m_data)。深拷贝。若是
B:m_data=A.m_data,是浅拷贝。在析构的时候会出错。 若禁止复制 把复制构造函数声明为 private。
2.赋值操作符
①参数为const类型引用。返回同类型引用。定义复制构造函数的时候也定义赋值操作符。在赋值之前释放当前对象的资源。
②判断传入参数和当前对象是否是同一个实例。否则delete时候会出错。
3.析构函数
对于动态分配的对象,在堆内存,需要手动delete,这时候调用析构函数。如果分配在栈上的,声明周期外自动调动。
所以对于函数中产生的局部变量,一定要小心。