
一、深拷贝和浅拷贝构造函数总结: 1、两个特殊的构造函数: (1)无参构造函数: 没有参数的构造函数 Class Test{ public: Test() { //这是一个无参构造函数 } }; 当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空;换句话来说,就是我们在类中,不用我们程序猿自己写,编译就自动提供了无参构造函数(只是我们肉眼看不到!) #include <iostream>#include <string> class Test{ //编译器默认给我们提供了一个无参构造函数,只是我们肉眼看不到 }; int main() { Test t; return 0; } 结果输出(编译时能够通过的): root@txp-virtual-machine:/home/txp# g++ test.cpproot@txp-virtual-machine:/home/txp# (2)拷贝构造函数: 参数为const class_name&的构造函数 class Test{public: Test(const Test& p) { } } 当类中没有定义拷贝构造函数时,编译器默认提供了一个拷贝构造函数,简单的进行成员变量的值赋值 #include <iostream>#include <string> class Test{ private: int i; int j; public: /* Test(const Test& p)编译器默认提供这样操作的 { i = p.i; j = p.j; }*/ }; int main() { Test t; return 0; } 输出结果(编译可以通过): root@txp-virtual-machine:/home/txp# g++ test.cpproot@txp-virtual-machine:/home/txp# (3)注意: 在写程序的时候,定义的类对象初始化时看属于哪种类型的: Test t;//对应无参构造函数Test t(1);//对应有参构造函数 Test t1; Test t2=t1;//对应拷贝构造函数 比如下面我定义的类对象属于无参构造函数(当然前提是你手写了其他构造函数,虽然说编译器会默认提供,但是既然要手写,那么三种构造函数就在定义类对象的时候按需求来写),如果只写了有参数构造函数,那么编译器就会报错: #include <iostream>#include <string> class Test{ private: int i; int j; public: Test(int a) { i = 9; j=8; } Test(const Test& p) { i = p.i; j = p.j; } }; int main() { Test t; return 0; } 输出结果: root@txp-virtual-machine:/home/txp# g++ test.cpptest.cpp: In function ‘int main()’: test.cpp:25:9: error: no matching function for call to ‘Test::Test()’ Test t; ^ test.cpp:25:9: note: candidates are: test.cpp:15:3: note: Test::Test(const Test&) Test(const Test& p) ^ test.cpp:15:3: note: candidate expects 1 argument, 0 provided test.cpp:10:3: note: Test::Test(int) Test(int a) ^ test.cpp:10:3: note: candidate expects 1 argument, 0 provided 4、拷贝构造函数的意义: (1)浅拷贝 拷贝后对象的物理状态相同 (2)深拷贝 拷贝后对象的逻辑状态相同 (3)编译器提供的拷贝构造函数只进行浅拷贝 代码版本一: #include <stdio.h>#include <string> class Test{ private: int i; int j; int *p; public: int getI() { return i; } int getJ() { return j; } int *getP() { return p; } Test(int a) { i = 2; j = 3; p = new int; *p = a; } void free() { delete p; } }; int main() { Test t1(3);//Test t1 3; Test t2 = t1; printf("t1.i = %d, t1.j = %d, t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP()); printf("t2.i = %d, t2.j = %d, t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP()); t1.free(); t2.free(); return 0; } 输出结果: root@txp-virtual-machine:/home/txp# g++ test.cpproot@txp-virtual-machine:/home/txp# ./a.out t1.i = 2, t1.j = 3, t1.p = 0x1528010 t2.i = 2, t2.j = 3, t2.p = 0x1528010 *** Error in `./a.out': double free or corruption (fasttop): 0x0000000001528010 *** Aborted (core dumped) 注解:出现了段错误,仔细分析,我们发现这里释放了堆空间两次(因为我们这里没有调用拷贝构造函数,也就是自己去写拷贝构造函数;所以这种情况是浅拷贝,不能释放两次堆空间):
代码版本二(加上拷贝构造函数): #include <stdio.h>#include <string> class Test{ private: int i; int j; int *p; public: int getI() { return i; } int getJ() { return j; } int *getP() { return p; } Test(int a) { i = 2; j = 3; p = new int; *p = a; } Test(const Test& t) { i = t.i; j = t.j; p = new int; *p = *t.p; } void free() { delete p; } }; int main() { Test t1(4); Test t2 = t1; printf("t1.i = %d, t1.j = %d, t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP()); printf("t2.i = %d, t2.j = %d, t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP()); t1.free(); t2.free(); return 0; } 输出结果: root@txp-virtual-machine:/home/txp# g++ test.cpproot@txp-virtual-machine:/home/txp# ./a.out t1.i = 2, t1.j = 3, t1.p = 0xb0a010 t2.i = 2, t2.j = 3, t2.p = 0xb0a030 注解:从打印的p地址空间来看,就知释放的两个对象的堆空间不同,不再是指向同一堆空间了;同时我们发现浅拷贝只是简单数值上的进行赋值而已;深拷贝不只是简单的值赋值,而是从内存的角度来看,是操作不同的内存。 5、什么时候需要进行深拷贝? (1)对象中有成员指代了系统中的资源
注意:一般来说,自定义拷贝构造函数(也就是我们自己手写的),必然需要实现深拷贝! 二、总结:
好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。 |