C++派生类的拷贝构造
一. 概述
通过几个简单的实验,回顾下派生类中拷贝构造的相关知识。
环境:Centos7 64位, g++ 4.8.5
在继承中,构造器与析构器均没有被继承下来。拷贝构造,也是一种构造,也没有被继承下来。
父类中,一部分成员需要拷贝构造来完成,子类,也有一部分成员需要拷贝构造来完成。子类中的内嵌子对象中的成员也需要拷贝构造来完成。
二. 实验过程
1.无自实现(系统默认)
派生类中,不自实现拷贝构造函数,看下系统默认的拷贝构造情况。
基类A,派生类C继承了基类A,派生类C中有一个内嵌子对象B bb。
通过下面的运行情况,对象c2拷贝了c1,派生类中调用了父类中默认的拷贝构造函数,内嵌子对象也是一样。
1 #include <iostream>
2
3 using namespace std;
4
5 class A
6 {
7 public:
8 A(int x = 10)
9 :a(x)
10 {
11 cout<<"constructor A()"<<endl;
12 }
13
14 int a;
15 };
16
17 class B
18 {
19 public:
20 B(int y = 20)
21 :b(y)
22 {
23 cout<<"constructor B()"<<endl;
24 }
25
26 int b;
27 };
28
29 class C: public A
30 {
31 public:
32 C(int x, int y, int z = 30)
33 :A(x), bb(y)
34 {
35 c = z;
36 cout<<"cosntructor C()"<<endl;
37 }
38
39 int c;
40 B bb;
41 };
42
43 int main()
44 {
45 C c1(42, 21, 14);
46 cout<<"c1: "<<c1.a<<" "<<c1.bb.b<<" "<<c1.c<<endl;
47
48 cout<<"----------"<<endl;
49 C c2(c1);
50 cout<<"c2: "<<c2.a<<" "<<c2.bb.b<<" "<<c2.c<<endl;
51
52 return 0;
53 }
运行结果如下:

达到了预期结果。
c2成功地拷贝了c1。根据打印结果,可知,c1对象在生成时,先调用了基类A的构造函数,然后是内嵌子对象bb的构造函数,最后是C自己的构造函数。
2.派生类中自实现拷贝构造函数,不显示调用父类、内嵌子对象中的拷贝构造函数
派生类C中,自实现拷贝构造函数,第11行-第14行,如下。
通过打印结果发现,派生类调用了基类的构造函数,而不是默认的拷贝构造函数。内嵌子对象也是一样。
对象c1和c2中的两个成员a, b结果均不一致,也就是说父类和内嵌子对象中的成员都没有被拷贝过来,c2中的a、b的值是父类、内嵌子对象中调用构造函数进行初始化而来的。此时,拷贝构造也没有什么意义了。无法达到拷贝的效果。
1 class C: public A
2 {
3 public:
4 C(int x, int y, int z = 30)
5 :A(x), bb(y)
6 {
7 c = z;
8 cout<<"cosntructor C()"<<endl;
9 }
10
11 C(const C &another)
12 {
13 c = another.c;
14 }
15
16 int c;
17 B bb;
18 };
运行结果如下:

3.派生类中自实现拷贝构造,显示调用父类、内嵌子对象中的拷贝构造函数
派生类C中添加显示调用,第12行代码。
注:A(another),将派生类对象赋值给父类的引用,用到了赋值兼容。
此时,派生类中的拷贝构造函数调用了基类中默认的拷贝构造函数。此时,浅拷贝也可以满足需求(关于浅拷贝与深拷贝)。
1 class C: public A
2 {
3 public:
4 C(int x, int y, int z = 30)
5 :A(x), bb(y)
6 {
7 c = z;
8 cout<<"cosntructor C()"<<endl;
9 }
10
11 C(const C &another)
12 :A(another), bb(another.bb)
13 {
14 c = another.c;
15 }
16
17 int c;
18 B bb;
19 };
运行结果如下:

运行结果符合预期,实现了拷贝的目的。
4.在3的基础上,如果需要实现深拷贝的目的,则父类中也需要自实现拷贝构造
类A,增加第10行-第14行代码
1 class A
2 {
3 public:
4 A(int x = 10)
5 :a(x)
6 {
7 cout<<"constructor A()"<<endl;
8 }
9
10 A(const A &another)
11 {
12 a = another.a;
13 cout<<"A(const A &another)"<<endl;
14 }
15
16 int a;
17 };
类B,增加第10行-第14行代码
1 class B
2 {
3 public:
4 B(int y = 20)
5 :b(y)
6 {
7 cout<<"constructor B()"<<endl;
8 }
9
10 B(const B &another)
11 {
12 b = another.b;
13 cout<<"B(const B &another)"<<endl;
14 }
15
16 int b;
17 };
运行结果如下:

根据打印结果可知, 对象c2在拷贝c1时,调用了基类和内嵌子对象的拷贝构造函数。
四. 总结
当派生类中不自实现拷贝构造时,默认调用父类的拷贝构造函数;
当派生类中自实现拷贝构造时,不做特殊处理(显示地调用父类的拷贝构造函数,包括系统默认和自实现拷贝构造函数),此时,只会调用父类的构造函数。此时,也失去了拷贝的意义,无法实现拷贝;
当派生类自实现拷贝构造,进行特殊处理(显示地调用父类的拷贝构造函数,包括系统默认和自实现的拷贝构造函数),此时,会调用父类的拷贝构造函数。
内嵌子对象与上面类似。
参考材料:
《C++基础与提高》 王桂林
C++派生类的拷贝构造的更多相关文章
- C++程序设计方法3:派生类对象的构造和析构过程
基类中的数据成员,通过继承成为派生类对象的一部分,需要在构造派生类对象的过程中调用基类构造函数来正确初始化: 若没有显示调用,则编译器会自动生成一个对基类的默认构造函数的调用. 若想要显示调用,则只能 ...
- c++学习笔记4,调用派生类的顺序构造和析构函数(一个)
测试源代码: //測试派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace ...
- 【C++ Primer 第15章】定义派生类拷贝构造函数、赋值运算符
学习资料 • 派生类的赋值运算符/赋值构造函数也必须处理它的基类成员的赋值 • C++ 基类构造函数带参数的继承方式及派生类的初始化 定义拷贝构造函数 [注意]对派生类进行拷贝构造时,如果想让基类的成 ...
- Chapter15:派生类
在C++语言中,基类将类型相关的函数与派生类不做改变直接继承的函数区别对待,对于某些函数,基类希望它的派生类各自定义适合自身的版本,此时基类就将这些函数声明为虚函数. 派生类必须将其继承而来的成员函数 ...
- 从零开始学C++之继承(二):继承与构造函数、派生类到基类的转换
一.不能自动继承的成员函数 构造函数 析构函数 =运算符 二.继承与构造函数 基类的构造函数不被继承,派生类中需要声明自己的构造函数. 声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类 ...
- C++ 派生类构造函数和析构函数
几个问题 一个类的各数据成员的构造顺序? 按他们在类定义中出现的先后顺序:先定义者先构造. 类的对象成员的构造函数与类自身的构造函数的执行顺序? 先执行对象成员的构造函数,再执行类自身的构造函数. 构 ...
- C++之旅:拷贝构造与友元
拷贝构造与友元 拷贝构造是在构造一个对象的时候将已有对象的属性拷贝给新的对象:友元可以让一个类的所有属性(主要是private)对特定的类开放 拷贝构造 如果没有复写拷贝构造函数,系统会帮我们默认生成 ...
- C++ | 继承(基类,父类,超类),(派生类,子类)
转载:https://blog.csdn.net/Sherlock_Homles/article/details/82927515 文章参考:https://blog.csdn.net/war1111 ...
- C++构造函数 & 拷贝构造函数 & 派生类的构造函数 & 虚继承的构造函数
构造函数 ,是一种特殊的方法 .主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 .特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数 ...
随机推荐
- Quill基本使用和配置 - DevUI
DevUI 是一款面向企业中后台产品的开源前端解决方案,它倡导沉浸.灵活.至简的设计价值观,提倡设计者为真实的需求服务,为多数人的设计,拒绝哗众取宠.取悦眼球的设计.如果你正在开发 ToB 的工具类产 ...
- 谷歌浏览器加载驱动(chromedriver)——selenium
http://chromedriver.storage.googleapis.com/index.html 可以到该网站下载对应的谷歌驱动器(注意:需要版本和操作系统对应,其中windows统一32的 ...
- 机器人路径规划其二 A-Star Algorithm【附动态图源码】
首先要说明的是,机器人路径规划与轨迹规划属于两个不同的概念,一般而言,轨迹规划针对的对象为机器人末端坐标系或者某个关节的位置速度加速度在时域的规划,常用的方法为多项式样条插值,梯形轨迹等等,而路径规划 ...
- 1、Centos7下安装Oracle11gR2及多实例
实验环境: 系统:2核8G内存60G硬盘,centos7.4: 优化操作:已经关闭了防火墙.selinux,/etc/hosts文件中以添加"172.16.1.92 slave-node2& ...
- zset如何解决内部链表查找效率低下
zset作为有序集合,内部基于跳表或者说索引的方式实现了数据的快速查找.解决了链表查询效率低下的痛点 前言 紧接前文我们学习了Redis中Hash结构.在里面我们梳理了字典这个重要的内部结构并分析了h ...
- Linux下实现MySQL数据库定时备份
咳~ 咳~ 为了避免数据操作失误.数据丢失.甚至删库跑路,简单做个数据备份吧 1.创建备份目录 # 习惯放在 local 下 cd /usr/local/ # 创建备份目录 mkdir backup ...
- rabbitmq概念简介
AMQP协议 AMQP: Advanced Message Queue,高级队列协议. 特征: 这是一个在进程间传递异步消息的网络协议,因此数据的发送方.接收方以及容器(MQ)都可以在不同的设备上. ...
- Linux:修改Ubuntu环境变量后bash找不到
1.问题显示 修改环境变量,导致命令全部失效 2.解决办法 #使用备份bin export PATH=/usr/bin:/bin 之后使用命令就可以了. 3.找到修改的环境变量 一般修改的环境变量 ...
- Cent OS下安装JDK11
自己云服务器以前装了个JDK1.7,最近发现出了jdk11,所以修改一下JDK版本: 我这里用的是Xshell和XFtp工具,下载地址:https://www.netsarang.com/downlo ...
- Redis的并发竞争问题,你用哪些方案来解决?
Redis的并发竞争问题,主要是发生在并发写竞争. 考虑到redis没有像db中的sql语句,update val = val + 10 where ...,无法使用这种方式进行对数据的更新. 假如有 ...