C++中基类和派生类的构造函数与析构函数的调用顺序分析

news2025/1/22 20:50:55

基类为B,派生类为C,直接上代码以及运行结果。

目录

思路分析

代码一

运行结果一

 代码二:B(i)改为b(i)

运行结果二

 代码三:加上B(i)

运行结果三

 代码四:删掉C类定义的B对象b,删除b(i)

运行结果四


思路分析

经评论区提醒,5月13日补充思路:首先,要知道基类和派生类的构造函数执行顺序是先执行基类的构造函数,再执行派生类的构造函数;而析构函数的执行顺序与构造函数的执行顺序刚好相反

其次,如果在派生类的构造函数中显式指定了调用基类的哪个构造函数,就会先执行这个构造函数;如果没有指定,则会调用基类的默认构造函数。

最后要注意的是,代码中的派生类C,除了继承一个基类B的整型变量b之外,还自定义了一个基类B的对象b,而这个对象b还包括了一个整型变量b,这三个b要注意区分。

为了方便,我们称B类的b变量为b1,C类的b对象的b变量为b2。

代码一中,由于C的构造函数显示指定了调用B的带参数的构造函数,所以会先输出“B`s constructor called.”,此时b1=i=5;然后由于C中定义的B类对象b并没有指定构造函数,所以会调用B类默认的构造函数,输出“B`s default constructor called.”,此时b2=0;然后调用C的带参构造函数,输出“C`s default constructor called.”,同时使得c的值为6;然后执行C类的Print函数,先执行B类的Print函数,输出b1的值为5,再输出c的值为6。最后按照与执行构造函数相反的顺序执行析构函数。

代码二中由于将B(i)改成了b(i),显示指定了C类的b对象调用的构造函数,而基类B调用哪个构造函数并没有被指定,因此先调用B类的默认构造函数,使得b1=0;然后调用C类的b对象的带参数的构造函数,使得b2=5;然后调用C的带参构造函数,同时使得c的值为6;然后执行C类的Print函数,先输出b1的值0,再输出c的值6;最后按照与执行构造函数相反的顺序执行析构函数。

代码三中由于加上了B(i),因此会先显示调用基类B的带参构造函数,再显示调用C类b对象的带参数的构造函数,使得b1=5,b2=5;然后调用C的带参构造函数,同时使得c的值为6;C类的Print函数先输出b1的值5,再输出c的值6;最后按照与执行构造函数相反的顺序执行析构函数。

代码四中,删掉C类定义的B对象b,删除b(i),因此只会显示调用基类B的带参构造函数,使得b1的值为5;然后调用C的带参构造函数,同时使得c的值为6;C的Print函数会先输出b1的值5,再输出c的值6;最后按照与执行构造函数相反顺序执行析构函数。

代码一

#include <iostream>
using namespace std;

class B{
public:
    B();
    B(int i);
    ~B();
    virtual void Print();
private:
    int b;
};
B::B(){
    b=0;
    cout<<"B`s default constructor called."<<endl;
}
B::B(int i){
    b=i;
    cout<<"B`s constructor called."<<endl;
}
B::~B(){
    cout<<"B`s destructor called."<<endl;
}
void B::Print(){
    cout<<b<<endl;
}

class C:public B{
public:
    C();
    C(int i,int j);
    ~C();
    void Print();
private:
    int c;
    B b;
};

C::C(){
    c=0;
    cout<<"C`s default constructor called."<<endl;
}
C::C(int i,int j):B(i){
    c=j;
    cout<<"C`s constructor called."<<endl;
}
C::~C(){
    cout<<"C`s destructor called."<<endl;
}
void C::Print(){
    B::Print();
    cout<<c<<endl;
}

int main()
{
    C obj(5,6);
    obj.Print();
    return 0;
}

运行结果一

 代码二:B(i)改为b(i)

#include <iostream>
using namespace std;

class B{
public:
    B();
    B(int i);
    ~B();
    virtual void Print();
private:
    int b;
};
B::B(){
    b=0;
    cout<<"B`s default constructor called."<<endl;
}
B::B(int i){
    b=i;
    cout<<"B`s constructor called."<<endl;
}
B::~B(){
    cout<<"B`s destructor called."<<endl;
}
void B::Print(){
    cout<<b<<endl;
}

class C:public B{
public:
    C();
    C(int i,int j);
    ~C();
    void Print();
private:
    int c;
    B b;
};

C::C(){
    c=0;
    cout<<"C`s default constructor called."<<endl;
}
C::C(int i,int j):b(i){
    c=j;
    cout<<"C`s constructor called."<<endl;
}
C::~C(){
    cout<<"C`s destructor called."<<endl;
}
void C::Print(){
    B::Print();
    cout<<c<<endl;
}

int main()
{
    C obj(5,6);
    obj.Print();
    return 0;
}

运行结果二

 代码三:加上B(i)

#include <iostream>
using namespace std;

class B{
public:
    B();
    B(int i);
    ~B();
    virtual void Print();
private:
    int b;
};
B::B(){
    b=0;
    cout<<"B`s default constructor called."<<endl;
}
B::B(int i){
    b=i;
    cout<<"B`s constructor called."<<endl;
}
B::~B(){
    cout<<"B`s destructor called."<<endl;
}
void B::Print(){
    cout<<b<<endl;
}

class C:public B{
public:
    C();
    C(int i,int j);
    ~C();
    void Print();
private:
    int c;
    B b;
};

C::C(){
    c=0;
    cout<<"C`s default constructor called."<<endl;
}
C::C(int i,int j):B(i),b(i){
    c=j;
    cout<<"C`s constructor called."<<endl;
}
C::~C(){
    cout<<"C`s destructor called."<<endl;
}
void C::Print(){
    B::Print();
    cout<<c<<endl;
}

int main()
{
    C obj(5,6);
    obj.Print();
    return 0;
}

运行结果三

 代码四:删掉C类定义的B对象b,删除b(i)

#include <iostream>
using namespace std;

class B{
public:
    B();
    B(int i);
    ~B();
    virtual void Print();
private:
    int b;
};
B::B(){
    b=0;
    cout<<"B`s default constructor called."<<endl;
}
B::B(int i){
    b=i;
    cout<<"B`s constructor called."<<endl;
}
B::~B(){
    cout<<"B`s destructor called."<<endl;
}
void B::Print(){
    cout<<b<<endl;
}

class C:public B{
public:
    C();
    C(int i,int j);
    ~C();
    void Print();
private:
    int c;
};

C::C(){
    c=0;
    cout<<"C`s default constructor called."<<endl;
}
C::C(int i,int j):B(i){
    c=j;
    cout<<"C`s constructor called."<<endl;
}
C::~C(){
    cout<<"C`s destructor called."<<endl;
}
void C::Print(){
    B::Print();
    cout<<c<<endl;
}

int main()
{
    C obj(5,6);
    obj.Print();
    return 0;
}

运行结果四

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/522094.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux使用全应用

一、CentOS安装Docker Docker CE 支持 64 位版本 CentOS 7&#xff0c;并且要求内核版本不低于 3.10&#xff0c; CentOS 7 满足最低内核的要求&#xff0c;所以我们在CentOS 7安装Docker。 基础命令 搜索镜像&#xff1a;docker search mysql 下载镜像&#xff1a;docker p…

[架构之路-197]-《软考-系统分析师》- 关键技术 - 问题分析阶段重要的四个任务

目录 前言&#xff1a; 一、信息系统/软件产品的问题分析概述 二、信息系统/软件产品的问题/痛点分析四步骤 步骤1、问题领域分析&#xff1a;研究遇到问题的业务领域&#xff08;诉求&#xff09; 步骤2、 领域问题和机会分析&#xff1a;分析业务领域的问题、痛点、难点…

计算机网络学习 一 (计算机网络体系结构)

计算机网络 基本概念 计算机网络是一个将分散的,具有独立功能的计算机系统. 简单来说,计算机网络就是一些互连的,自治的计算机系统的集合 分类 广义上:是一个资源共享的系统. 资源共享上: 1.目的–资源共享 2.组成单元–分布在不同地理位置的多台独立的"自治计算机"…

第十四届蓝桥杯青少组模拟赛Python真题 (2022年11月8日)

第十四届蓝桥杯青少组模拟赛Python真题 (2022年11月8日) 编程题 第 1 题 问答题 二进制位数 十进制整数2在十进制中是1位数&#xff0c;在二进制中对应10&#xff0c;是2位数。 十进制整数22在十进制中是2位数&#xff0c;在二进制中对应10110&#xff0c;是5位数。 请问十…

Linux高级---k8s之service服务

文章目录 一、service基本概念二、service类型三、service的使用1、实验环境准备2、ClusterIP类型的Service3、HeadLiness类型的Service4、NodePort类型的Service5、LoadBalancer类型的Service6、ExternalName类型的Service 一、service基本概念 在kubernetes中&#xff0c;pod…

【Java多线程编程】线程的六种状态

前言&#xff1a; 在我们进行多线程编程&#xff0c;脑海里会想到线程运行的状态到底是什么&#xff1f;因此我整理出这线程的状态这篇博文。线程的状态分为六种&#xff1a;新建状态&#xff08;NEW&#xff09;、就绪状态&#xff08;RUNNABLE&#xff09;、阻塞状态&#xf…

1-Linux环境安装JDK

Linux环境安装JDK 准备&#xff1a; ① Linux 环境 本文中Linux环境为 CentOS Linux 7 可使用以下命令查询 linux 系统版本&#xff1a; hostnamectl② 准备JDK包 进入官网 https://www.oracle.com/java/technologies/downloads/#java17下载对应jdk包 此处使用以前下载的旧…

Linux驱动编程(驱动程序基石)(下)

一、中断的线程化处理 复杂、耗时的事情&#xff0c;尽量使用内核线程来处理。上节视频介绍的工作队列用起来挺简单&#xff0c;但是它有一个缺点&#xff1a;工作队列中有多个 work&#xff0c;前一个 work 没处理完会影响后面的 work。解决方法有很多种&#xff0c;比如干脆…

String类的学习笔记(下):字符串拼接以及StringBuilder和StringBuffer的学习

本文介绍了String类对字符串进行拼接的方法 和拼接字符串的效率分析 以及能对字符串内容进行修改的StringBuilder和StringBuffer类其常用方法和区别 , 最后介绍了两个字符串经典面试题 StringBuilder和StringBuffer的学习 一.String类概括二.StringBuilder和StringBuffer1.字符…

是未来的超级计算机还是只是一场炒作?

随着科技的飞速发展和创新&#xff0c;量子计算技术逐渐成为了人们关注的热点话题。量子计算作为一种前沿的计算方式&#xff0c;具有超强的运算能力和突破性的创新潜力&#xff0c;因此备受瞩目。然而&#xff0c;随着各大公司和机构纷纷加入到这一领域的竞争中&#xff0c;一…

超详细github配置(仔细看,看完不会,你怪我)

github的重要性&#xff1a; 网络时代的程序员必备。 github的作用&#xff1a; 版本管理多人协作开源共享 常用方案&#xff1a; gitTortoiseGitgithub [Tortoise&#xff0c;程序员常称其为小乌龟&#xff0c;小海龟] 安装配置步骤 1.注册 GitHub: Where the world bu…

服务(第二十二篇)主从复制和读写分离

主从复制原理&#xff1a; 首先主节点会开启二进制日志&#xff0c;从节点会开启中继日志&#xff0c;从节点会开启io线程检测主节点是否有更新&#xff0c;如果更新了就会向主节点请求二进制事件&#xff0c;主会开启dump线程发送二进制事件&#xff0c;然后保存在从节点的中…

假如面试官让你十分钟完成双向循环链表

&#x1f48c; 博客内容&#xff1a;假如面试官让你十分钟完成双向循环链表&#xff0c;多一秒都不行 &#x1f600; 作  者&#xff1a;陈大大陈 &#x1f680; 个人简介&#xff1a;一个正在努力学技术的准前端&#xff0c;专注基础和实战分享 &#xff0c;欢迎私信&…

大前端技能讲解:NodeJS、Npm、Es6、Webpack

文章目录 1. 基础概述2. Nodejs2.1 Nodejs 了解和快速入门2.2 Nodejs 实现 Httpserver 服务&#xff08;实现请求响应&#xff09;2.3 Nodejs 操作 MySQL 数据库 3. ES63.1 ES6 的概述3.2 ES6 的语法&#xff1a;let 和 const 命令3.3 ES6 的语法&#xff1a;模板字符串3.4 ES6…

基于SSM的在线电影购票系统设计与实现【附源码】

基于SSM的在线电影购票系统设计与实现 互联网的不断迅猛发展&#xff0c;每个行业都在寻找新的机会&#xff0c;都在从传统的人工方式向先进的信息化过度。随着人民生活水平的提高伴随的精神文化层次的享受&#xff0c;而现代互联网时代人们的重要精神消费之一是电影行业&…

NAS +AList实现云盘映射(本地硬盘扩容大法)

准备工具&#xff1a; 1&#xff09;Alist的docker &#xff1a;xhofe/alist 2&#xff09;RailDrive软件 安装&#xff1a; 1&#xff09;安装alist的docker 注意一定要给读写权限&#xff0c;装载路径和我一样 端口一般和容器端口一致 环境变量 网络桥接就行 记得勾选自…

【Prompting】ChatGPT Prompt Engineering开发指南(1)

ChatGPT Prompt Engineering开发指南1 Prompting指南设置 提示原则策略1&#xff1a;使用分隔符清楚地指示输入的不同部分策略2&#xff1a;要求结构化输出策略3&#xff1a;让模型检查条件是否满足策略4: “Few-shot”提示 原则2&#xff1a;给模型时间“思考”策略1&#xff…

idea新建springboot项目并提交码云仓库

新建springboot项目 平常我们在使用联网方式新建springboot项目时总是会遇到连接失败等这种情况 IDEA创建项目&#xff0c;本质是从官网创建并下载项目&#xff0c;然后导入本地。 创建项目连接失败&#xff0c;一般是外国网站的原因导致连接超时&#xff0c;解决方式很简单&a…

C++linux高并发服务器项目实践 day11

Clinux高并发服务器项目实践 day11 线程同步互斥锁死锁读写锁读写锁相关操作函数 生产者消费者模型条件变量信号量 线程同步 线程的主要优势在于&#xff0c;能够通过全局变量来共享信息。不过&#xff0c;这种便捷的共享是有代价的:必须确保多个线程不会同时修改同一变量&…

LabVIEWCompactRIO 开发指南17 网络流

LabVIEWCompactRIO 开发指南17 网络流 网络流类似于队列函数&#xff0c;因为它们是基于FIFO的&#xff0c;但与队列函数不同的是&#xff0c;网络流具有网络作用域。它们是为通过以太网进行无损、高吞吐量数据通信而设计和优化的&#xff0c;并且它们具有增强的连接管理功能…