同类对象之间可以通过赋值运算符 = 互相赋值。如果没有经过重载, = 的作用就是将赋值号左侧对象的值一一赋值给左侧对象,这相当于值的拷贝,称作"浅拷贝"。如果赋值对象中涉及指针或引用,则它们之间是相互关联的,一个值变化了,另一个值也跟着变化。因为对象中的指针指向的是同一个内存地址。
重载赋值运算符后,赋值语句的功能是将一个对象中指针成员变量指向的内容复制到另一个对象中指针成员变量指向的地方,这样的拷贝称作”深拷贝“。
浅拷贝示例
#include <iostream>
using namespace std;
class Pointer
{
public:
int a;
int* p;
Pointer() {
a = 100;
p = new int(10);
}
Pointer(const Pointer& temp) {
if (this != &temp) {
a = temp.a;
p = temp.p; // 浅拷贝
}
}
~Pointer() {
// 当对象p1消亡时,需要释放构造函数中动态申请的空间,也就是那个整型值占据的空间,
// 当对象p2消亡时,也会试图释放这个空间,重复释放同一块空间会产生错误
//if (p != NULL) delete p;
cout << "析构" << endl;
}
};
int main()
{
Pointer p1;
Pointer p2(p1);//使用复制构造函数
Pointer p3 = p1;//使用复制构造函数
cout << "\n初始化后,各对象的值及内存地址" << endl;
cout << "对象名\t 对象地址 a的值 p中的值 p指向的值 p的地址" << endl;
cout << "p1:\t" << &p1 << ",\t" << p1.a << ",\t" << p1.p << ",\t" << *p1.p << ",\t" << &p1.p << endl;
cout << "p2:\t" << &p2 << ",\t" << p2.a << ",\t" << p2.p << ",\t" << *p2.p << ",\t" << &p2.p << endl;
cout << "p3:\t" << &p3 << ",\t" << p3.a << ",\t" << p3.p << ",\t" << *p3.p << ",\t" << &p3.p << endl;
*p1.p = 20;
p2.a = 300;
cout << "\n修改后,各对象的值及内存地址" << endl;
cout << "对象名\t 对象地址 a的值 p中的值 p指向的值 p的地址" << endl;
cout << "p1:\t" << &p1 << ",\t" << p1.a << ",\t" << p1.p << ",\t" << *p1.p << ",\t" << &p1.p << endl;
cout << "p2:\t" << &p2 << ",\t" << p2.a << ",\t" << p2.p << ",\t" << *p2.p << ",\t" << &p2.p << endl;
cout << "p3:\t" << &p3 << ",\t" << p3.a << ",\t" << p3.p << ",\t" << *p3.p << ",\t" << &p3.p << endl;
return 0;
}
结果
初始化后,各对象的值及内存地址
对象名 对象地址 a的值 p中的值 p指向的值 p的地址
p1: 007FFDC4, 100, 00CF5FE0, 10, 007FFDC8
p2: 007FFDB4, 100, 00CF5FE0, 10, 007FFDB8
p3: 007FFDA4, 100, 00CF5FE0, 10, 007FFDA8
修改后,各对象的值及内存地址
对象名 对象地址 a的值 p中的值 p指向的值 p的地址
p1: 007FFDC4, 100, 00CF5FE0, 20, 007FFDC8
p2: 007FFDB4, 300, 00CF5FE0, 20, 007FFDB8
p3: 007FFDA4, 100, 00CF5FE0, 20, 007FFDA8
析构
析构
析构
分析
分析:
当对象p1消亡时,需要释放构造函数中动态申请的空间,也就是那个整型值占据的空间,二当对象p2消亡时,也会试图释放这个空间,重复释放同一块空间会产生错误。
当使用
Pointer p4;
p4 = p1;
则对象p4中成员变量p原来指向的空间被忽略了,创建对象p4时,构造函数已经为p4中的成员变量分配了空间,并赋予了初值10。语句p4 = p1,将p1中成员变量的值分别赋值给p4的各成员变量,p4中成员变量p指向了p1中p指针指向的地址,而丢失了原来指向的地址,如果没有其他的指针指向这个地址,则这块内存永远不会被释放,成为垃圾内存。
深拷贝示例
#include <iostream>
using namespace std;
class Pointer
{
public:
int a;
int* p;
Pointer() {
a = 100;
p = new int(10);
}
Pointer(const Pointer& temp) {
if (this != &temp) {
a = temp.a;
p = new int();
*p = *temp.p; // 深拷贝
}
}
~Pointer() {
if (p != NULL) delete p;
}
Pointer& operator=(const Pointer& c) {
if (this == &c) return *this; // 避免a=a这样的赋值
delete this->p; // 释放原来的空间
this->p = new int(*c.p);//申请新的空间
return *this;
}
};
int main()
{
Pointer p1;
Pointer p2(p1);//使用复制构造函数
Pointer p3;
p1 = p1; //测试赋值运算符重载
p3 = p1; //使用复制构造函数
cout << "\n初始化后,各对象的值及内存地址" << endl;
cout << "对象名\t 对象地址 a的值 p中的值 p指向的值 p的地址" << endl;
cout << "p1:\t" << &p1 << ",\t" << p1.a << ",\t" << p1.p << ",\t" << *p1.p << ",\t" << &p1.p << endl;
cout << "p2:\t" << &p2 << ",\t" << p2.a << ",\t" << p2.p << ",\t" << *p2.p << ",\t" << &p2.p << endl;
cout << "p3:\t" << &p3 << ",\t" << p3.a << ",\t" << p3.p << ",\t" << *p3.p << ",\t" << &p3.p << endl;
*p1.p = 20;
p2.a = 300;
cout << "\n修改后,各对象的值及内存地址" << endl;
cout << "对象名\t 对象地址 a的值 p中的值 p指向的值 p的地址" << endl;
cout << "p1:\t" << &p1 << ",\t" << p1.a << ",\t" << p1.p << ",\t" << *p1.p << ",\t" << &p1.p << endl;
cout << "p2:\t" << &p2 << ",\t" << p2.a << ",\t" << p2.p << ",\t" << *p2.p << ",\t" << &p2.p << endl;
cout << "p3:\t" << &p3 << ",\t" << p3.a << ",\t" << p3.p << ",\t" << *p3.p << ",\t" << &p3.p << endl;
return 0;
};
结果
初始化后,各对象的值及内存地址
对象名 对象地址 a的值 p中的值 p指向的值 p的地址
p1: 0097FBA0, 100, 00E1FA50, 10, 0097FBA4
p2: 0097FB90, 100, 00E1FA80, 10, 0097FB94
p3: 0097FB80, 100, 00E15F50, 10, 0097FB84
修改后,各对象的值及内存地址
对象名 对象地址 a的值 p中的值 p指向的值 p的地址
p1: 0097FBA0, 100, 00E1FA50, 20, 0097FBA4
p2: 0097FB90, 300, 00E1FA80, 10, 0097FB94
p3: 0097FB80, 100, 00E15F50, 10, 0097FB84
分析
复制构造函数中,原来是进行的浅拷贝,所以整数值及指针值都被复制过来,两个对象中指针成员变量的值相同,也就是都指向同一个位置。新的复制构造函数中,新申请了一个保存整数值的空间,两个对象中指针不再是相同的,也就是说,它们分别指向各自的单元,仅有单元中的值是相同的。析构函数中,因为各对象中指针指向的位置是不同的,所以释放时也不会出现问题。
当执行语句p3 = p1时,使用p1的值初始化p3,函数中,释放掉指针原来执行的空间,再重新申请新的空间,这样可以保证不会与参数对象中指针指向的空间相同。然后使用值*c.p初始化新申请的空间。
来自《c++程序涉及》