【c++继承篇】--继承之道:在C++的世界中编织血脉与传承
目录
- 引言
- 一、定义
- 二、继承定义格式
- 2.1定义格式
- 2.2继承关系和访问限定符
- 2.3继承后子类访问权限
- 三、基类和派生类赋值转换
- 四、继承的作用域
- 4.1同名变量
- 4.2同名函数
- 五、派生类的默认成员构造函数
- 5.1**构造函数调用顺序:**
- 5.2**析构函数调用顺序:**
- 5.3调用关系
- 六、继承和组合

引言
今天学习继承,继承(Inheritance)
是面向对象编程中的一种核心概念,它允许一个类(子类)从另一个类(父类)派生,继承父类的属性和方法。
一、定义
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。
我们通过一个简单的代码示例来说明下:
class Person
{
public :void print(){cout << " name:" << _name << " id: " << _id << endl;}
protected:string _name= "per";int _id = 134;
};class Student :public Person
{
protected:int _stuid;
};
在上述代码中,Student 类就是继承了父类Person,继承父类的成员(成员函数+成员变量)都会变成子类的一部分。父类person就是基类,子类Student也就是派生类。
二、继承定义格式
2.1定义格式
2.2继承关系和访问限定符
继承方式有public 继承、protected 继承、private 继承。访问限定符有public 访问、protected访问、
private访问。
2.3继承后子类访问权限
类成员/继承方式 | public 继承 |
---|---|
基类public | 派生类的public成员 |
基类 protected | 派生类的protected成员 |
基类 private | 派生类中不可见 |
总:
- 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私
有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面
都不能去访问它。 - 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在
派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。 - 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
- 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
- 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强
三、基类和派生类赋值转换
派生类对象 可以赋值给基类的对象 / 基类的指针 / 基类的引用 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。
相反 基类成员无法赋值给派生类成员。
如:
class Person
{
protected :string _name; // 姓名string _sex; // 性别int _age; // 年龄
};
class Student : public Person
{
public :int _No; // 学号
};
void Test ()
{Student s ;// 1.子类对象可以赋值给父类对象/指针/引用Person p = s ;Person* p1 = &s;Person& p2 = s;//2.基类对象不能赋值给派生类对象// 3.基类的指针可以通过强制类型转换赋值给派生类的指针p1 = &s;Student* s1 = (Student*)pp; // 这种情况转换时可以的。s1->_No = 10;
}
四、继承的作用域
继承的作用域决定了从基类继承到派生类的成员(包括变量和方法)的访问权限。
在c++继承体系中基类和派生类都有独立的作用域。当子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义。(在子类成员函数中,可以使用 基类::基类成员 显示访问)
4.1同名变量
在下面代码中,基类和派生类都有一个_num这个变量。
class Person
{
protected:string name = "xiaolizi";int _num = 111;};
y隐藏/重定义 子类和父类有同名成员
class Student :public Person
{
public:void print(){cout << "名字:" << name << endl;cout << _num << endl;}
protected:int _num = 333;
};
int main()
{Student s;s.print();
}
输出结果:
若果想要打印基类的_num则只需要在print函数里面加入::限定符:
void print(){cout << "名字:" << name << endl;cout <<person:: _num << endl;}
4.2同名函数
如果基类和派生类都出现名字相同的函数,会发现什么?
如下:
class A
{
public:void fun(){cout << "func()" << endl;}
};
class B : public A
{
public:void fun(int i){A::fun();cout << "func(int i)->" <<i<<endl;}
};
void Test()
{B b;b.fun(2);
}
输出结果:
B中的fun和A中的fun不是构成重载,因为不是在同一作用域
B中的fun和A中的fun构成隐藏,成员函数满足函数名相同就构成隐藏。
要访问A中的func函数,需要加 :: 限定符
五、派生类的默认成员构造函数
在类中有六个默认成员函数(分别是:默认构造函数、拷贝构造函数、拷贝赋值运算符、析构函数、移动构造函数、移动赋值运算符),一起看看:
5.1构造函数调用顺序:
-
创建派生类对象时,从最顶层的基类开始,逐层向下调用构造函数,直到派生类。
-
接着,按照派生类中成员变量的声明顺序初始化成员变量(若成员是对象,则调用其构造函数)。
-
最后,执行派生类构造函数体中的代码。
5.2析构函数调用顺序:
-
销毁派生类对象时,首先调用派生类的析构函数。
-
然后,按照成员变量声明的逆序调用成员变量的析构函数(若成员是对象)。
-
最后,从最顶层的基类开始,逐层向上调用析构函数,直到派生类的基类
代码演示:
#include <iostream>
using namespace std;class Base {
public:Base() { cout << "Base constructor\n"; }~Base() { cout << "Base destructor\n"; }
};class Derived : public Base {
public:Derived() { cout << "Derived constructor\n"; }~Derived() { cout << "Derived destructor\n"; }
};int main() {Derived d;return 0;
}
运行结果:
Base constructor
Derived constructor
Derived destructor
Base destructor
在上述代码中,
当对象 d 被创建时,首先调用 Base 类的构造函数,然后调用 Derived 类的构造函数。
当对象销毁时,首先调用 Derived 类的析构函数,最后调用 Base 类的析构函数。
构造调用总结:
- 基类构造函数首先调用。
- 成员对象构造函数按成员声明的顺序调用。
- 派生类构造函数最后调用
析构调用总结:
- 成员对象析构顺序:按照它们在类定义中的声明顺序销毁。
- 继承关系:析构函数的调用顺序是先派生类,后基类。
5.3调用关系
- 派生类的构造函数必须调用基类的构造函数来初始化基类的成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表中显式调用基类的一个构造函数。
- 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化
- 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才保证派生类对象先清理派生类成员再清理基类成员的顺序。
示意图如下:
六、继承和组合
组合是通过在类中包含其他类的对象来实现的,通常是通过成员变量来持有其他对象的实例。这种方法强调“拥有”关系(has-a)。继承则是is-a关系。
组和用法:
#include <iostream>
using namespace std;// 类 Engine:发动机
class Engine {
public:void start() {cout << "Engine starting..." << endl;}
};// 类 Car:汽车
class Car {
private:Engine engine; // Car 类拥有 Engine 类的对象
public:void drive() {engine.start(); // 使用 Engine 类的功能cout << "Car is driving..." << endl;}
};int main() {Car car;car.drive(); // 调用 Car 类的方法,间接使用 Engine 类的方法return 0;
}
在上述代码中:
- Car 类组合了一个 Engine 对象作为其成员变量。
- Car 类的 drive() 方法中,首先调用 Engine 类的 start() 方法,然后输出 “Car is driving…”。
注:
实际尽量多去用组合。组合的耦合度低,代码维护性好。不过继承也有用武之地的,有些关系就适合继承那就用继承,另外要实现多态,也必须要继承。类之间的关系可以用继承,可以用组合,就用组合。
相关文章:

【c++继承篇】--继承之道:在C++的世界中编织血脉与传承
目录 引言 一、定义二、继承定义格式2.1定义格式2.2继承关系和访问限定符2.3继承后子类访问权限 三、基类和派生类赋值转换四、继承的作用域4.1同名变量4.2同名函数 五、派生类的默认成员构造函数5.1**构造函数调用顺序:**5.2**析构函数调用顺序:**5.3调…...

分布式系统通信解决方案:Netty 与 Protobuf 高效应用
分布式系统通信解决方案:Netty 与 Protobuf 高效应用 一、引言 在现代网络编程中,数据的编解码是系统设计的一个核心问题,特别是在高并发和低延迟的应用场景中,如何高效地序列化和传输数据对于系统的性能至关重要。随着分布式系…...

计算机网络 (54)系统安全:防火墙与入侵检测
前言 计算机网络系统安全是确保网络通信和数据不受未经授权访问、泄露、破坏或篡改的关键。防火墙和入侵检测系统(IDS)是维护网络系统安全的两大核心组件。 一、防火墙 定义与功能 防火墙是一种用来加强网络之间访问控制的特殊网络互联设备,它…...
stack底层实现细节
一、stack 和 queue 在 STL 中 stack 和 queue 已经不算是容器了,而是容器适配器,适配器模式也是常用的模式之一,体现在 stack 和 queue 中就是他们两个的实现不是单独写的,而是复用了前面合适的优秀的STL 容器的代码而实现的具有…...

工业相机 SDK 二次开发-Halcon 插件
本文介绍了 Halcon 连接相机时插件的使用。通过本套插件可连接海康 的工业相机。 一. 环境配置 1. 拷贝动态库 在 用 户 安 装 MVS 目 录 下 按 照 如 下 路 径 Development\ThirdPartyPlatformAdapter 找到目录为 HalconHDevelop 的文 件夹,根据 Halcon 版本找到对…...

map和set的使用(一)详解
文章目录 序列式容器和关联式容器map和set的介绍set构造和迭代器遍历和insertfinderaseswapclearcountlower_bound和upper_boundmultiset和set的对比 set的二个题目题目解析算法原理代码介绍一个找差集的算法同步算法题目解析算法原理代码 map构造遍历initiaizer_list 序列式容…...

ARP 表、MAC 表、路由表、跨网段 ARP
文章目录 一、ARP 表1、PC2、路由器 - AR22203、交换机 - S57004、什么样的设备会有 ARP 表? 二、MAC 表什么样的设备会有 MAC 表? 三、路由表什么样的设备会有路由表? 四、抓取跨网段 ARP 包 所谓 “透明” 就是指不用做任何配置 一、ARP 表…...
37.构造回文字符串问题|Marscode AI刷题
1.题目 问题描述 小C手中有一个由小写字母组成的字符串 s。她希望构造另一个字符串 t,并且这个字符串需要满足以下几个条件: t 由小写字母组成,且长度与 s 相同。t 是回文字符串,即从左到右与从右到左读取相同。t 的字典序要小…...

ssm-mybatisPlus学习笔记
注意!mybatisPlus只能够进行单表操作,其他的仍需要mybatis 1.快速入门 编写启动类 MapperScan("com.atguigu.mapper") SpringBootApplication public class MainApplication {public static void main(String[] args) {SpringApplication.r…...
【算法学习笔记】35:扩展欧几里得算法求解线性同余方程
线性同余方程问题 线程同余方程问题是指 a x ≡ b ( m o d m ) ax \equiv b~(mod~m) ax≡b (mod m),给定 a a a、 b b b和 m m m,找到一个整数 x x x使得该方程成立,即使得 a x m o d m b ax~mod~mb ax mod mb,随便返回任何一个…...

线性规划:机器学习中的优化利器
一、线性规划的基本概念 线性规划(Linear Programming, LP)是运筹学中数学规划的一个重要分支,用于在一组线性不等式的约束条件下,找到线性目标函数的最大值或最小值。其问题可以表述为: 在一组线性约束条件 s.t.&am…...
Ubuntu开发中的问题
1.退出anaconda指令:conda deactivate 2.Linux系列:一打开终端就默认进入conda的base环境,取消方法 在终端输入conda config --show,会显示所有的配置信息,然后利用conda config --set来修改此配置: conda config --se…...
MAC 地址转换为标准大写格式
// ConvertToStandardMac 将 MAC 地址转换为标准格式,确保每个字节都是两位,并且字母是大写的 func ConvertToStandardMac(mac string) (string, error) { // 分割 MAC 地址的每一部分 parts : strings.Split(mac, ":") // 确保每部分是两…...

使用插件SlideVerify实现滑块验证
作者gitee地址:https://gitee.com/monoplasty/vue-monoplasty-slide-verify 使用步骤: 1、安装插件 npm install --save vue-monoplasty-slide-verify 2、在main.js中进行配置 import SlideVerify from vue-monoplasty-slide-verify; Vue.use(SlideV…...
深入探索 Nginx 的高级用法:解锁 Web 服务器的强大潜能
在当下互联网技术飞速发展的浪潮中,Nginx 凭借其轻量级、高性能的特性,在 Web 服务器和反向代理服务器领域脱颖而出,成为众多开发者和运维工程师的得力工具。它不仅能高效处理静态资源,在负载均衡、反向代理等方面也表现出色。然而…...
(01)搭建开发环境
1.安装虚拟机软件 VMware Workstation Pro 17 2.虚拟机安装ubuntu20.4系统 3.安装VMtools工具 4.安装vim编辑器 sudo apt install vim 4.安装SSH服务 选择下载源为:http://mirrors.aliyun.com/ubuntu在线安装:sudo apt-get install openssh-serv…...
Win11桌面右键刷新选项在二级界面的修正方法
win10已经被弃用了,现在的win11在桌面右键时,“刷新”按钮在二级界面。除此以外,在资源管理器中浏览文件的时候,很多其他选项也都被放在了二级界面,非常不方便。接下来介绍一个把右键菜单栏中的所有选项都显示在一级界…...

配电室防静电地板通常用哪种
配电室是指带有低压负荷的室内配电场所,包含变压器、配电柜、开关设备等,主要为低压用户配送电能。为防止设备故障、避免火灾爆炸、保护人员安全等均会安装防静电地板。那么配电室防静电地板通常用哪种? 一、全钢防静电地板 1. 全钢三聚氰胺…...

【重庆市乡镇界】面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移内容测评
标题中的“最新重庆市乡镇界面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移最新”指的是一个地理信息系统(GIS)的数据集,特别设计用于ArcGIS软件。这个数据集包含了重庆市所有乡镇的边界信息,以Shapefile(.shp…...

68,[8] BUUCTF WEB [RoarCTF 2019]Simple Upload(未写完)
<?php // 声明命名空间,遵循 PSR-4 自动加载规范,命名空间为 Home\Controller namespace Home\Controller;// 导入 Think\Controller 类,以便扩展该类 use Think\Controller;// 定义 IndexController 类,继承自 Think\Control…...
Parasoft C++Test软件单元测试_实例讲解(对多次调用的函数打桩)
系列文章目录 Parasoft C++Test软件静态分析:操作指南(编码规范、质量度量)、常见问题及处理 Parasoft C++Test软件单元测试:操作指南、实例讲解、常见问题及处理 Parasoft C++Test软件集成测试:操作指南、实例讲解、常见问题及处理 进阶扩展:自动生成静态分析文档、自动…...

2025年全国青少年信息素养大赛复赛C++算法创意实践挑战赛真题模拟强化训练(试卷3:共计6题带解析)
2025年全国青少年信息素养大赛复赛C++算法创意实践挑战赛真题模拟强化训练(试卷3:共计6题带解析) 第1题:四位数密码 【题目描述】 情报员使用4位数字来传递信息,同时为了防止信息泄露,需要将数字进行加密。数据加密的规则是: 每个数字都进行如下处理:该数字加上5之后除…...

Maven工程演示
软件:idea 一、项目创建 操作截图file -> New -> Projectnextnext -> Name:工程名称;Location:项目路径;项目创建完成;文件夹基本样例:(如果不完整自己创建即可)MANIFEST.MF内容 二、导入依赖 …...
【前端优化】使用speed-measure-webpack-plugin分析前端运行、打包耗时,优化项目
记录下 项目安装speed-measure-webpack-plugin 打包分析: 修改vue.config.js文件 speed-measure-webpack-plugin进行构建速度分析,需要包裹整个 configureWebpack 配置 const originalConfig {publicPath: /,assetsDir: assets,parallel: true,devS…...

Python打卡训练营学习记录Day41
DAY 41 简单CNN 知识回顾 数据增强卷积神经网络定义的写法batch归一化:调整一个批次的分布,常用与图像数据特征图:只有卷积操作输出的才叫特征图调度器:直接修改基础学习率 卷积操作常见流程如下: 1. 输入 → 卷积层 →…...

亚马逊商品评论爬取与情感分析:Python+BeautifulSoup实战(含防封策略)
一、数据爬取模块(Python示例) import requests from bs4 import BeautifulSoup import pandas as pd import timeheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36,Accept-Language: en-US }def scrape_amazon_re…...
B端产品经理如何快速完成产品原型设计
B 端产品经理的原型设计需兼顾业务流程复杂度、功能逻辑性和操作效率,快速完成原型的核心在于结构化梳理需求、复用成熟组件、借助高效工具、聚焦核心场景。以下是具体方法和步骤: 一、明确需求优先级:先框架后细节 1. 梳理业务流程&#x…...

C++之string的模拟实现
string 手写C字符串类类的基本结构与成员变量一、构造函数与析构函数二、赋值运算符重载三、迭代器支持四、内存管理与扩容机制五、字符串操作函数六、运算符重载总结 手写C字符串类 从零实现一个简易版std::string 类的基本结构与成员变量 namespace zzh { class string { …...

Qt实现csv文件按行读取的方式
Qt实现csv文件按行读取的方式 场景:我有一个保存数据的csv文件,文件内保存的是按照行保存的数据,每行数据是以逗号为分隔符分割的文本数据。如下图所示: 现在,我需要按行把这些数据读取出来。 一、使用QTextStream文本流的方式读取 #include <QFile>void readfil…...

vue2使用el-tree实现两棵树间节点的拖拽复制
原文链接:两棵el-tree的节点跨树拖拽实现 参照这篇文章,把它做成组件,新增左侧树(可拖出)被拖节点变灰提示; 拖拽中: 拖拽后: TreeDragComponent.vue <template><!-- …...