拷贝的两种方式:浅拷贝、深拷贝
浅拷贝就是对象的数据成员之间的简单赋值,如果设计了类而没有提供拷贝构造函数,当用该类的一个对象去给另一个对象赋值是所执行的过程就是浅拷贝。
如:
class A
{
public:
A(int _data) :data(_data){}
A(){}
private:
int data;
};
int main
{
A a(5), b = a;
}
---------------------------------------------------------------
b = a;----就是浅拷贝,执行后b.data = 5;
当数据成员中没有指针时,浅拷贝是可行的,但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象结束时,会调用两次析构函数,而导致指针悬挂现象(如果一个地方指针既不为空,也没有设置为指向一个已知的对象,这样的指针称为悬挂指针)
深拷贝和浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来存储数据,从而也就解决了指针悬挂。
如:
class A
{
public:
A (int _size):size(_size)
{
data = new int[size];
}
A(){};
A(const A& _A):size(_A.size)
{
data = new int [size];
}
~A()
{
delete[] data;
}
private:
int *data;
int size;
};
int main()
{
A a(5), b = a;
}
例程(浅拷贝):--转载
class Cperson
{
public:
Cperson(int age);
void Print(void);
private:
int m_age;
};
Cperson::Cperson(int age):m_age(age)
{
}
void Cperson::Print(void)
{
cout << "My age is " << m_age << endl;
}
void main(void)
{
Cperson Tom(10);
Tom.Print();
Cperson Jim(Tom);
Jim.Print();
}
运行结果:
My age is 10
My age is 10
结果分析:
对应语句Cperson Jim(Tom) 编译器将自动生成一个默认的拷贝构造函数。
错误的浅拷贝:
class Cperson
{
public:
Cperson(int age,char *name);
~Cperson();
void Print(void);
private:
int m_age;
char *m_name;
};
Cperson::Cperson(int age, char *name)
{
m_name = new char[strlen(name) + 1 ];
if(m_name != NULL)
strcpy(m_name, name);
m_age = age;
cout << m_name << endl;
}
Cperson::~Cperson()
{
cout << " 析构:" << m_name << endl;
if(m_name != NULL)
delete m_name;
}
void Cperson::Print(void)
{
cout << "My age is " << m_age << " My name is " << m_name << endl;
}
void main(void )
{
Cperson Tom(10, "Tom");
Tom.Print();
Cperson Jim(Tom);
Jim.Print();
}
程序出现错误:
执行语句Cperson Tom(10, "Tom") 时,用new动态开辟了一段内存,用来存放"Tom"
执行Cperson Jim(Tom) 时只是将Tom 的成员Tom.m_age, Tom.m_name 赋值给了Jim 相应的成员。
此时 Tom.m_name Jim.m_name 指向同一内存空间, 系统并没有给Jim.m_name开辟相应的内存空间。
执行完Jim.Print()后,开始执行析构函数,析构函数的执行顺序和构造函数的执行顺序相反,即先执行Jim的析构函数,释放掉Jim.m_name 的内存空间。析构Tom是空间就会出问题。
深拷贝:
class Cperson
{
public:
Cperson(int age, char *name);
Cperson(Cperson& per);
~Cperson();
void Print(void);
private:
int m_age;
char *m_name;
};
Cperson::Cperson(int age, char *name)
{
m_name = new char[strlen(name) + 1];
if(m_name != NULL)
strcpy(m_name, name);
m_age = age;
}
Cperson::Cperson(Cperson& per)
{
m_name = new char[strlen(per.m_name) + 1];
if(m_name != NULL)
strcpy(m_name, per.m_name);
m_age = per.m_age;
}
Cperson::~Cperson()
{
delete m_name;
}
void Cperson::Print()
{
cout << "My age is " << m_age << "My name is "<< m_name << endl;
}
void main(void)
{
Cperson Tom(10, "Tom");
Tom.Print();
Cperson Jim(Tom);
Cperson.Print();
}
自定义拷贝构造函数后,就没有问题了, 在实际中应尽量避免浅拷贝。