拷贝构造函数的调用时机

  1. 使用一个已经创建完毕的对象初始化一个新对象

  2. 以值传递的方式给函数传值

  3. 以值方式返回局部对象

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;
 }

 

值传递对象输出:

image-20211217103423592

 
//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是不是同一个

image-20211217111559281

拷贝构造是类内有指针的情况下必写的(赋值运算符重载是有需要的话)

老师这两节课是在讲,如果你有了一个对象,如何用函数再创造出一个来,拷贝构造就是完全复制一个现有对象

调用规则:

image-20211217145512098

浅拷贝和深拷贝

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区重新申请空间进行拷贝操作

image-20211217163355010

image-20211217163430662

报错

image-20211217163522597

问题解释:

p1在进行有参初始化时,在堆区申请了一个空间,p1的height指针就指向这个空间,p2在进行拷贝初始化时使用的是编译器提供的浅拷贝,浅拷贝是对成员变量的简单赋值,所以p2的height指针=p1的height指针,即两个height指针指向堆区的同一个地址,函数test01结束后,p1和p2把同一个空间释放了两次,所以程序崩了


image-20211217172704482

两个指针指向同一块堆空间,局部变量存在栈中,具有先进后出的特点,所以test1中后创建的p2先被释放,执行析构函数,释放掉堆区内存空间,再释放p1指向的堆区内存空间,由于已经被释放掉,非法操作,所以报错

这是浅拷贝带来的问题:堆区的内存重复释放

解决方法:利用深拷贝,再开辟一块堆空间存放175

image-20211217201239469

image-20211217201643769

 /*浅拷贝与深拷贝*/
 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;
 }

如果属性有在堆区开辟的,一定要自己写拷贝构造函数,防止浅拷贝带来的问题

P110结束

来源:b站黑马

posted on 2021-12-17 20:23  托马斯源  阅读(46)  评论(0编辑  收藏  举报