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运算符一起使用在创建对象的语句中 .特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数 ...
随机推荐
- 05:JS(01)
内容概要 JavaScript编程语言开头 数值类型 字符类型 布尔值 null与undefined 对象 数组 自定义对象 流程控制 函数 内置对象 时间对象 正则对象 JSON对象 BOM操作(j ...
- Zab协议 (史上最全)
文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...
- 「模拟8.23」one递推,约瑟夫
前置芝士约瑟夫问题 这样大概就是板子问题了 考场的树状数组+二分的60分暴力??? 1 #include<bits/stdc++.h> 2 #define int long long 3 ...
- 【题解】Luogu p2964 BZOJ 2017[Usaco2009 Nov]硬币游戏
题目描述 Farmer John's cows like to play coin games so FJ has invented with a new two-player coin game c ...
- 安卓控件RecycleView的简单使用
RecycleView的使用 目录 RecycleView的使用 技术概述 技术详述 遇到问题和解决 总结 参考文献 技术概述 RecycleView是谷歌官方对ListView的改进(并不是替代), ...
- 『无为则无心』Python基础 — 14、Python流程控制语句(while循环语句)
目录 1.什么是循环结构 2.while循环 (1)while循环的语法 (2)while循环的应用 3.while语句的死循环 4.break和continue 5.while循环嵌套 (1)应用场 ...
- Linux基本命令精讲
一.Shell Linux系统中运行的一种特殊程序 在用户和内核之间充当"翻译官 用户登录 Linux系统时,自动加载一个 Shell程序 Bash是 LinuxShell系统中默认使用的程 ...
- Jenkins自动化CI&CD流水线
1 环境说明 主机名称 IP cpu核数/内存/硬盘 安装软件 用途 controlnode 172.16.1.120 2/2/60 git 代码仓库 slavenode1 172.16.1.121 ...
- Linux Netfilter框架分析
目录 Netfilter框架 Netfilter的5个hook点 netfilter协议栈数据流分析 连接跟踪conntrack conntrack连接跟踪表条目 连接跟踪表大小 管理连接跟踪表 ip ...
- 使用Docker的同学注意了,这10个坑小心中招了
Docker容器优点容器已经成为企业IT基础设施中必不可少的部分,它具有许多的优点,比如: 1 容器是不可变的--操作系统,库版本,配置,文件夹和应用程序都包装在容器内.你保证在质量检查中测试过的同一 ...