c++ 拷贝构造函数(重点在内含指针的浅拷贝和深拷…
2019-10-25 06:26:36来源:博客园 阅读 ()
c++ 拷贝构造函数(重点在内含指针的浅拷贝和深拷贝)
今天同事问了一个关于拷贝构造函数的问题,类中包含指针的情况,今天就来说说c++的拷贝构造函数。
c++的拷贝构造函数是构造函数的一种,是对类对象的初始化,拷贝构造函数只有一个参数就是本类的引用。
注意,默认构造函数(即无参构造函数)不一定存在,但是拷贝构造函数总是会存在。
下面是一个拷贝构造函数的例子。
1 #include<iostream> 2 using namespace std; 3 class A{ 4 public: 5 int a; 6 A(int value){ 7 a = value; 8 } 9 void show(){ 10 cout<<a<<endl; 11 } 12 }; 13 int main(){ 14 A test_a(10); 15 test_a.show(); 16 17 A test_b(test_a); 18 test_b.show(); 19 20 return 0; 21 }
输出结果为:
10 10
如果编写了拷贝构造函数,则默认拷贝构造函数就不存在了。下面是一个非默认拷贝构造函数的例子。
1 #include<iostream> 2 using namespace std; 3 class A{ 4 public: 5 int a; 6 A(int value){ 7 a = value; 8 } 9 A(A& tmp){ 10 a = tmp.a; 11 cout<<"call copy construct"<<endl; 12 } 13 void show(){ 14 cout<<a<<endl; 15 } 16 }; 17 int main(){ 18 A test_a(10); 19 test_a.show(); 20 21 A test_b(test_a); 22 test_b.show(); 23 24 return 0; 25 }
输出结果为:
10 call copy construct 10
拷贝构造函数被调用的三种情况
拷贝构造函数在以下三种情况下会被调用。
1) 当用一个对象去初始化同类的另一个对象时,会引发拷贝构造函数被调用。例如,下面的两条语句都会引发拷贝构造函数的调用,用以初始化 test_b。
1 A test_b(test_a); 2 A test_b = test_a;
这两条语句是等价的。
注意,第二条语句是初始化语句,不是赋值语句。赋值语句的等号左边是一个早已有定义的变量,赋值语句不会引发拷贝构造函数的调用。例如:
1 A test_a,test_b; 2 test_b = test_a;
这条语句不会引发拷贝构造函数的调用,因为 test_b 早已生成,已经初始化过了。
2) 如果函数 F 的参数是类 A 的对象,那么当 F 被调用时,类 A 的拷贝构造函数将被调用。换句话说,作为形参的对象,是用复制构造函数初始化的,而且调用拷贝构造函数时的参数,就是调用函数时所给的实参。
3) 如果函数的返冋值是类 A 的对象,则函数返冋时,类 A 的拷贝构造函数被调用。换言之,作为函数返回值的对象是用拷贝构造函数初始化 的,而调用拷贝构造函数时的实参,就是 return 语句所返回的对象。例如下面的程序:
1 #include<iostream> 2 using namespace std; 3 class A{ 4 public: 5 int a; 6 A(int value){ 7 a = value; 8 } 9 A(A& tmp){ 10 a = tmp.a; 11 cout<<"call copy construct"<<endl; 12 } 13 void show(){ 14 cout<<a<<endl; 15 } 16 }; 17 A Func() { 18 A test_a(4); 19 return test_a; 20 } 21 int main(){ 22 Func().show(); 23 24 return 0; 25 }
输出结果:
call copy construct 4
针对于第三条,有些编译器可能会有以下的结果:
4
这是因为编译器编译的时候进行了优化,函数返回值对象就不用拷贝构造函数初始化了,这其实并不符合 C++的标准。
浅拷贝和深拷贝
重头戏来了,内含指针的拷贝构造函数,C++是如何实现的呢,来看个例子:
1 #include<iostream> 2 using namespace std; 3 class A{ 4 public: 5 int a; 6 int *p; 7 A(int value1, int value2){ 8 a = value1; 9 p = new int(value2); 10 } 11 ~A(){ 12 delete p; 13 } 14 15 void show(){ 16 cout<<a<<endl; 17 cout<<p<<endl; 18 cout<<*p<<endl; 19 } 20 }; 21 22 int main(){ 23 A test_a(10,20); 24 test_a.show(); 25 26 A test_b(test_a); 27 test_b.show(); 28 29 return 0; 30 }
输出结果如下:
10 0xf19010 20 10 0xf19010 20 *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0000000000f19010 *** ...
可以看到对于class A 的对象 test_a 和 test_b 指针p 指向了同一块内存,在对象析构的时候被析构了两次导致了crash,这就是我们常说的浅拷贝。
因此,在我们日常编写代码的时候特别需要注意这一点,对于指针我们需要相应的开辟一块新的内存,将指向的值拷贝过来,也就是所谓的深拷贝,下面是正确的写法:
1 #include<iostream> 2 using namespace std; 3 class A{ 4 public: 5 int a; 6 int *p; 7 A(int value1, int value2){ 8 a = value; 9 p = new int(value2); 10 } 11 A(A& tmp){ 12 a = tmp.a; 13 p = new int(* tmp.p); 14 } 15 ~A(){ 16 delete p; 17 } 18 19 void show(){ 20 cout<<a<<endl; 21 cout<<p<<endl; 22 cout<<*p<<endl; 23 } 24 }; 25 26 int main(){ 27 A test_a(10,20); 28 test_a.show(); 29 30 A test_b(test_a); 31 test_b.show(); 32 33 return 0; 34 }
输出结果如下:
10 0xd4d010 20 10 0xd4d030 20
原文链接:https://www.cnblogs.com/r-yan/p/11727889.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:P2995 [USACO10NOV]牛的照片(树状数组,逆序对)
下一篇:测试博客
- C++ 转换函数搭配友元函数 2020-06-10
- C++ 自动转换和强制类型转换(用户自定义类类型) 2020-06-10
- C++ rand函数 2020-06-10
- C++ 友元函数 2020-06-10
- C++ 运算符重载 2020-06-10
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash