1.拷贝构造
1.1 为什么存在
- 当类的数据成员中没有指针类型的变量时,直接对两个对象进行赋值没有问题。
- 但是一旦类的数据成员含有指针变量,那么直接对这两个对象进行赋值操作之后,这两个对象的指针都将指向同一块内存。这时,一旦其中一个对象生存期结束,释放该内存,那么另一个对象的指针就变成了野指针!这对程序危害很大
1.2 定义
拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:
- 通过使用另一个同类型的对象来初始化新创建的对象。
- 复制对象把它作为参数传递给函数。
- 复制对象,并从函数返回这个对象。
2.赋值构造
什么时候调用拷贝构造,什么时候调用赋值构造呢??当出现下面两种情况的时候调用赋值构造
- 对象直接赋值给另一个对象,且接受值的对象已经初始化过
- 对象以值传递方式从函数返回,且接受返回值的对象已经初始化过
3.代码
赋值构造与拷贝构造原理类似,两个放在一起对比,就可以把知识闭环成体系,加深理解
#include <iostream>
using namespace std;
class Line
{
public:
Line( );
Line( int len ); // 简单的构造函数
Line( const Line &obj); // 拷贝构造函数,会覆盖默认拷贝构造函数
Line& operator= (const Line& a); //赋值构造函数
~Line(); // 析构函数
//注:默认的拷贝构造是位复制,即复制地址;重写后的是按值复制
// private:
int *x;
};
Line::Line()
{
cout << "调用默认构造函数" << endl;
x = new int;
*x = 10;
printf ("stack address: %x, point: %x, value: %d\n", this, x, *x);
}
// 成员函数定义,包括构造函数
Line::Line(int value)
{
cout << "调用参数构造函数" << endl;
// 为指针分配内存
x = new int;
*x = value;
printf ("stack address: %x, point: %x, value: %d\n", this, x, *x);
}
Line::Line(const Line &obj)
{
cout << "调用拷贝构造函数并为指针 x 分配内存" << endl;
x = new int; //指针
*x = *obj.x; // 拷贝值
printf ("stack1 address: %x, point: %x, value: %d\n", this, x, *x);
}
Line & Line::operator=(const Line &obj)
{
cout << "调用赋值构造函数并为指针 x 分配内存" << endl;
x = new int; //指针
*x = *obj.x; // 拷贝值
printf ("stack2 address: %x, point: %x, value: %d\n", this, x, *x);
}
Line::~Line(void)
{
printf ("释放内存 address: %x, point: %x, value: %d\n", this, x, *x);
delete x;
}
void display(Line obj)
{
//在这个方法里面obj是副本,所以会调用一下拷贝构造函数初始化副本
//初始化完之后,进行业务处理,用完之后就释放掉了
cout << "line 值 : " << *obj.x <<endl;
}
Line newObj(void)
{
Line line1(10);
printf ("stack3 address: %x, point: %x, value: %d\n", &line1, line1.x, *line1.x);
return line1;
}
int main( )
{
//1 浅拷贝
Line line1(10);//1.0 普通构造函数
printf ("global.line1 address: %x, point: %x, value: %d\n", &line1, line1.x,*line1.x);
cout << "===========" << endl;
//【注意】 !!! 下面两行不会调用拷贝构造,但是会调用赋值构造!
Line line2;
line2 = line1; // 1.1 调用赋值构造函数 【赋值构造情景1】
// Line line2 = line1; // 1.2 调用拷贝构造函数【普通】
printf ("global.line2 address: %x, point: %x, value: %d\n", &line2, line2.x,*line2.x);
cout << "===========" << endl;
Line line3(line1); //1.3 调用拷贝构造函数【普通】
printf ("global.line3 address: %x, point: %x, value: %d\n", &line3, line3.x,*line3.x);
cout << "===========" << endl;
display(line1); //1.4 调用拷贝构造【副本】:方法里面是个副本,因要生成副本所以肯定要拷贝构造了
printf ("global.line1 address: %x, point: %x, value: %d\n", &line1, line1.x,*line1.x);
cout << "===========" << endl;
line2 = newObj();//1.5 调用赋值构造函数 【赋值构造情景2】
printf ("global.line2 address: %x, point: %x, value: %d\n", &line2, line2.x,*line2.x);
cout << "===========" << endl;
//2 深拷贝.....
return 0;
}