拷贝构造函数的调用时机
-
使用一个已经创建完毕的对象初始化一个新对象
-
以值传递的方式给函数传值
-
以值方式返回局部对象
Person类
class Person { public: Person() { cout << "Person类的无参构造" << endl; } Person(string name,int a) { this->name = name; this->age = a; cout << "Person类的有参构造" << endl; } //拷贝构造函数:引用是传入张三本体进行拷贝,const是防止修改张三本体 Person(const Person &p) { this->age = p.age;//将传入的人身上的所有属性拷贝到我身上 this->name = p.name; cout << "Person类的拷贝构造函数" << endl; } int age; string name; void show() { cout << this->name << endl; cout << this->age << endl; } ~Person() { cout << "Person类的析构函数" << endl; } };
调用
//1. 使用一个已经创建完毕的对象初始化一个新对象 void test() { Person p1 = Person("小明", 20); Person p2 = Person(p1); } //2. 以值传递的方式给函数传值 void doWork(Person p){} void test1() { Person p; doWork(p); } int main() { test1(); //值传递会复制出一个形参在函数中进行操作,当参数为对象时会调用拷贝构造函数 system("pause"); return 0; }
值传递对象输出:
//3. 以值方式返回局部对象 Person doWork1() { Person p; return p; } void test2() { Person p = doWork1(); } int main() { test2(); //doWork1()中以值方式返回一个对象p,返回的p不是原来创建的对象,而是创建了一个新对象返回,在这个过程中调用了拷贝构造函数 system("pause"); return 0; }
侧面验证一下doWork1()中的p和test2()中的p是不是同一个
拷贝构造是类内有指针的情况下必写的(赋值运算符重载是有需要的话)
老师这两节课是在讲,如果你有了一个对象,如何用函数再创造出一个来,拷贝构造就是完全复制一个现有对象
调用规则:
浅拷贝和深拷贝
浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间进行拷贝操作
报错
问题解释:
p1在进行有参初始化时,在堆区申请了一个空间,p1的height指针就指向这个空间,p2在进行拷贝初始化时使用的是编译器提供的浅拷贝,浅拷贝是对成员变量的简单赋值,所以p2的height指针=p1的height指针,即两个height指针指向堆区的同一个地址,函数test01结束后,p1和p2把同一个空间释放了两次,所以程序崩了
两个指针指向同一块堆空间,局部变量存在栈中,具有先进后出的特点,所以test1中后创建的p2先被释放,执行析构函数,释放掉堆区内存空间,再释放p1指向的堆区内存空间,由于已经被释放掉,非法操作,所以报错
这是浅拷贝带来的问题:堆区的内存重复释放
解决方法:利用深拷贝,再开辟一块堆空间存放175
/*浅拷贝与深拷贝*/ class Person { public: Person() { cout << "Person类的无参构造" << endl; } Person(int a,int height) { this->age = a; this->height= new int(height); cout << "Person类的有参构造" << endl; } Person(const Person &p) { this->age = p.age;//将传入的人身上的所有属性拷贝到我身上 //this->height = p.height; 这是编译器默认的方式 //深拷贝方式 this->height = new int(*p.height); cout << "Person类的拷贝构造函数" << endl; } int age; int* height; ~Person() { if (height != NULL) { delete height;//把指针指向的堆空间释放 height = NULL;//把指针本身释放 } cout << "Person类的析构函数" << endl; } }; void test1() { Person p1(18,175); cout << "p1的年龄:" << p1.age << endl; cout << "p1的身高:" << *p1.height << endl; Person p2(p1); cout << "p2的年龄:" << p2.age << endl; cout << "p2的身高:" << *p2.height << endl; } int main() { test1(); system("pause"); return 0; }
如果属性有在堆区开辟的,一定要自己写拷贝构造函数,防止浅拷贝带来的问题