C++的基类和派生类构造函数
基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。

在设计派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数完成,但是大部分基类都有 private 属性的成员变量,它们在派生类中无法访问,更不能使用派生类的构造函数来初始化。
这种矛盾在C++继承中是普遍存在的,解决这个问题的思路是:在派生类的构造函数中调用基类的构造函数。
下面的例子展示了如何在派生类的构造函数中调用基类的构造函数:
#include<iostream>using namespace std;//基类Peopleclass People{protected:char *m_name;int m_age;public:People(char*, int);};People::People(char *name, int age): m_name(name), m_age(age){}//派生类Studentclass Student: public People{private:float m_score;public:Student(char *name, int age, float score);void display();};//People(name, age)就是调用基类的构造函数Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }void Student::display(){cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<"。"<<endl;}int main(){Student stu("小明", 16, 90.5);stu.display();return 0;}
运行结果为:小明的年龄是16,成绩是90.5。
请注意第 23 行代码:

Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
People(name, age)就是调用基类的构造函数,并将 name 和 age 作为实参传递给它,m_score(score)是派生类的参数初始化表,它们之间以逗号,隔开。也可以将基类构造函数的调用放在参数初始化表后面:
Student::Student(char *name, int age, float score): m_score(score), People(name, age){ }
但是不管它们的顺序如何,派生类构造函数总是先调用基类构造函数再执行其他代码(包括参数初始化表以及函数体中的代码),总体上看和下面的形式类似:
Student::Student(char *name, int age, float score){People(name, age);m_score = score;}
当然这段代码只是为了方便大家理解,实际上这样写是错误的,因为基类构造函数不会被继承,不能当做普通的成员函数来调用。换句话说,只能将基类构造函数的调用放在函数头部,不能放在函数体中。另外,函数头部是对基类构造函数的调用,而不是声明,所以括号里的参数是实参,它们不但可以是派生类构造函数参数列表中的参数,还可以是局部变量、常量等,例如

Student::Student(char *name, int age, float score): People("小明", 16), m_score(score){ }
构造函数的调用顺序
从上面的分析中可以看出,基类构造函数总是被优先调用,这说明创建派生类对象时,会先调用基类构造函数,再调用派生类构造函数,如果继承关系有好几层的话,例如:
A --> B --> C
那么创建 C 类对象时构造函数的执行顺序为:
A类构造函数 --> B类构造函数 --> C类构造函数
构造函数的调用顺序是按照继承的层次自顶向下、从基类再到派生类的。还有一点要注意,派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的。
以上面的 A、B、C 类为例,C 是最终的派生类,B 就是 C 的直接基类,A 就是 C 的间接基类。
C++ 这样规定是有道理的,因为我们在 C 中调用了 B 的构造函数,B 又调用了 A 的构造函数,相当于 C 间接地(或者说隐式地)调用了 A 的构造函数,如果再在 C 中显式地调用 A 的构造函数,那么 A 的构造函数就被调用了两次,相应地,初始化工作也做了两次,这不仅是多余的,还会浪费CPU时间以及内存,毫无益处,所以 C++ 禁止在 C 中显式地调用 A 的构造函数。
基类构造函数调用规则
事实上,通过派生类创建对象时必须要调用基类的构造函数,这是语法规定。换句话说,定义派生类构造函数时最好指明基类构造函数;如果不指明,就调用基类的默认构造函数(不带参数的构造函数);如果没有默认构造函数,那么编译失败。请看下面的例子:
#include <iostream>using namespace std;//基类Peopleclass People{public:People(); //基类默认构造函数People(char *name, int age);protected:char *m_name;int m_age;};People::People(): m_name("xxx"), m_age(0){ }People::People(char *name, int age): m_name(name), m_age(age){}//派生类Studentclass Student: public People{public:Student();Student(char*, int, float);public:void display();private:float m_score;};Student::Student(): m_score(0.0){ } //派生类默认构造函数Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }void Student::display(){cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<"。"<<endl;}int main(){Student stu1;stu1.display();Student stu2("小明", 16, 90.5);stu2.display();return 0;}
运行结果:xxx的年龄是0,成绩是0。
小明的年龄是16,成绩是90.5。
创建对象 stu1 时,执行派生类的构造函数Student::Student(),它并没有指明要调用基类的哪一个构造函数,从运行结果可以很明显地看出来,系统默认调用了不带参数的构造函数,也就是People::People()。
创建对象 stu2 时,执行派生类的构造函数Student::Student(char *name, int age, float score),它指明了基类的构造函数。
在第 27 行代码中,如果将People(name, age)去掉,也会调用默认构造函数,第 37 行的输出结果将变为:xxx的年龄是0,成绩是90.5。
如果将基类 People 中不带参数的构造函数删除,那么会发生编译错误,因为创建对象 stu1 时需要调用 People 类的默认构造函数, 而 People 类中已经显式定义了构造函数,编译器不会再生成默认的构造函数。
相关文章:
C++的基类和派生类构造函数
基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生…...
C语言中对json格式数据的解析和封装
首先需要调库:#include <cJSON.h> Json的数据结构介绍: /* The cJSON structure: */ typedef struct cJSON { /*next/prev允许您遍历数组/对象链。或者,使用GetArraySize/GetArrayItem/GetObjectItem */ struct cJSON *next; struct c…...
RT-Thread自动初始化机制
自动初始化机制是指初始化函数不需要被显示调用,只需要在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中被执行。 int rt_hw_usart_init(void) {rt_hw_serial_register(&serial1, "uart1",RT_DEVICE_FLAG_RDWR | RT_DEVICE_FL…...
在本地搭建Jellyfin影音服务器,支持公网远程访问影音库的方法分享
文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及,各种各样的使用需求也被开发出来&…...
强盛集团面试题实战(持续更新)
目录 第一章、面试题1.1)王:8月301.2)1.3) 第二章、2.1)2.2)2.3) 第三章、3.1)3.2)3.3) 第四章、4.1)4.2)4.3) 友情提醒:先…...
golang 协程的实现原理
核心概念 要理解协程的实现, 首先需要了解go中的三个非常重要的概念, 它们分别是G, M和P, 没有看过golang源代码的可能会对它们感到陌生, 这三项是协程最主要的组成部分, 它们在golang的源代码中无处不在. G (goroutine) G是goroutine的头文字, goroutine可以解释为受管理的…...
go gin 参数绑定常用验证器
https://pkg.go.dev/github.com/go-playground/validator/v10#readme-baked-in-validations min 最小max 最大len 长度限制gt 大于eq 等于ne 不等于eqfield 与某个字段值一样nefield 与某个字段值不一样oneof 枚举 ,以空格分开startswithendswithdive 数组 package mainimpor…...
多用户商城系统常见的安全性和数据保护措施有哪些?
电子商务的迅速发展,越来越多的企业选择搭建多用户商城系统来扩展业务。然而,随之而来的是对数据安全和保护的日益关注。在选择多用户商城系统时,我们需要考虑一系列的安全性和数据保护措施,以确保商城系统的稳定性和用户数据的完…...
如何在WSL上导入任何Linux发行版
文章目录 一、准备1. 开启WSL相关功能2. 升级WSL3. 设置默认的wsl版本 二、通过 Microsoft Store 安装 Linux1. 查看 Microsoft Store 有哪些可安装的 Linux 发行版2. 安装 Linux 发行版3. 查看已安装的 Linux 发行版4. 启动Linux发行版 三、通过Linux发行商提供的tar文件安装1…...
汽车自适应巡航系统车距控制策略研究
1 引言 自适应巡航控制( Adaptive Cruise Control,ACC) 是汽车驾驶辅助系统的重要组成部分,其作用是根据车距传感器探测到本车( ACC 车辆) 与主目标车辆( 前车) 之间的相对位置和相对速度信息,自动调节ACC 车辆的节气门开度或部分制动力矩( 即…...
鸿蒙系列-如何更好地使用 ArkUI 的 Image 组件?
如何使用好 ArkUI 的 Image 组件? 开发者经常需要在应用中显示一些图片,例如:按钮中的logo、网络图片、本地图片等。在应用中显示图片需要使用 Image 组件实现,Image支持多种图片格式,包括png、jpg、bmp、svg和gif&am…...
机器学习简介[01/2]:简单线性回归
Python 中的机器学习简介:简单线性回归 一、说明 简单线性回归为机器学习提供了优雅的介绍。它可用于标识自变量和因变量之间的关系。使用梯度下降,可以训练基本模型以拟合一组点以供未来预测。 二、技术背景 这是涵盖回归、梯度下降、分类和机器学习的其…...
Kubernetes技术--k8s核心技术yaml资源编排
(1).引入 我们可以使用kubectl实现单行指令的操作,但是这样做的坏处是不复用,所以为了更好的实现对一系列资源的编排工作。kuberntes中使用一种叫做资源清单文件(yaml)来实现对资源管理和资源对象编排部署。 (2).概述 yaml是一种标记语言。为了强调这种语言以数据做为中心,而…...
clickhouse-配置解释
详细内容看官网文档 一、全局服务配置 1.配置详解 名称含义默认值allow_use_jemalloc_memory允许使用 jemalloc 内存1(布尔)asynchronous_heavy_metrics_update_period_s更新异步指标的时间段(以秒为单位)120asynchronous_metr…...
基于亚马逊云科技无服务器服务快速搭建电商平台——性能篇
使用 Serverless 构建独立站的优势 在传统架构模式下,如果需要进行电商大促需要提前预置计算资源以支撑高并发访问,会造成计算资源浪费并且增加运维工作量。本文介绍一种新的部署方式,将 WordPress 和 WooCommerce 部署在 Amazon Lambda 中。…...
LINQ详解(查询表达式)
什么是LINQ? LINQ(语言集成查询)是将查询功能直接集成到C#中。数据查询表示简单的字符串,在编译时不会进行类型检查和IntelliSense(代码补全辅助工具)支持。 在开发中,通常需要对不同类型的数据源了解不同的查询语句,如SQL数据库…...
【DEVOPS】现状篇
0. 目录 1. 前言2. 现状2.1 需求管理2.2 开发流程2.3 测试流程2.4 部署流程2.5 维护阶段 3. 后记4. 相关 1. 前言 一直以来,深感内部工程化能力欠缺,急于将事情向前推进,总是希望能够向前走几步,再走几步。 可惜的是,…...
Linux文件管理知识:查找文件(第二篇)
Linux文件管理知识:查找文件(第二篇) 上篇文章详细介绍了linux系统中查找文件的工具或者命令程序locate和find命令的基本操作。那么,今天这篇文章紧接着查找文件相关操作内容介绍。 Find命令所属操作列表中的条目,有助于我们想要…...
医疗小程序:让服务更高效,用户体验更优化
随着移动互联网的快速发展,小程序已经成为了一个热门的开发方向。医疗健康类小程序也不例外,拥有广泛的市场需求和前景。本文将为你提供一份完整的医疗健康类小程序开发攻略,帮助你快速开发上线一个专业成熟的小程序商城。 一、选择合适的小程…...
C++11 std::transform函数使用说明
std::transform是C标准库中的一个算法,它用于对输入范围内的元素进行操作,并将结果存储在输出范围内。这个算法特别适合于将一种数据类型转换为另一种数据类型。 函数定义在头文件algorithm中 std::transform的基本语法如下: std::transfor…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...
