利用暑假时间将C++从头到尾认真学习一下,特别是指针、面向对象、泛型等特性!
参考书籍为《C++ Primer Plus》
拷贝构造函数
拷贝构造函数用于将一个对象复制到新创建的对象中,一般会在以下情形被调用:
- 使用已初始化对象赋值新创建的对象;
- 对象作为函数参数值传递
- 对象从函数中值返回
拷贝构造函数分为浅拷贝和深拷贝,浅拷贝包括默认的,可以理解为仅值复制,对于指针成员,新复制的并没有拥有新空间,与原者指向同处,这就会出现问题,当原者调用析构函数后会把该空间释放!而深拷贝则会创建一片新空间,本文的所有例子基于Person类(基类)和Worker类(扩展类)进行说明,代码如下:
1 | #Person类 person.h |
person.cpp:
1 |
|
1 | #Worker类 worker.h |
下面来看看默认的浅拷贝:
1 | Person p1=Person("Xiao Hong",8,"LinYi",'F'); |
(注意这里显式调用构造函数也会触发拷贝构造函数,但是编译器优化掉了,在本篇文章后面会进行说明)会发现结果如下:
1 | Xiao Hong Bye Person! |
p2在析构时name其实已经释放了
此时我们采用深拷贝,在person.h中添加以下声明:
1 | Person(const Person &person); |
person.cpp中如下扩展:
1 | Person::Person(const Person &person){ |
注意这里要传引用!
然后结果会变为:
1 | 深拷贝构造函数 |
下面介绍之前说的那三种使用场景。
使用已初始化对象赋值新创建的对象
上面那个例子中用到的,还有就是继承中,如下所示:
1 | Person p1=Worker("Xiao Ming",10,"LinYi",'M',500000,"Ali"); |
这个时候也会调用拷贝构造函数,执行结果为:
1 | 深拷贝构造函数 |
由此推断执行顺序应该是:
生成Worker对象—>深拷贝生成新Person对象—>Worker析构—>基类Person析构—>拷贝后的Person析构
对象作为函数参数值传递
定义函数printObj:
1 | void printObj(const Person p){ |
执行结果为:
1 | 深拷贝构造函数 |
对象从函数中值返回
定义函数getObj:
1 | Person getObj() |
但是没有预想到调用深拷贝构造函数,查阅博文知是编译器进行了优化,要加-fno-elide-constructors
选项
加上后神奇的一幕发生了!原本Person p=Person("Xiao Ming",10,"LinYi",'M');
这种显示调用构造函数也会调用深拷贝,结果如下:
1 | 深拷贝构造函数 |
所以有两条析构,而隐式调用则没有Person p1("Xiao Ming",10,"LinYi",'M');
然后调用getObj的结果如下所示:
1 | 深拷贝构造函数 |