【c++继承篇】--继承之道:在C++的世界中编织血脉与传承

news2025/1/18 11:08:04

目录

    • 引言
  • 一、定义
  • 二、继承定义格式
    • 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派生类中不可见

总:

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私
    有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面
    都不能去访问它。
  2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在
    派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
  3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
  4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
  5. 在实际运用中一般使用都是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调用关系

  • 派生类的构造函数必须调用基类的构造函数来初始化基类的成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表中显式调用基类的一个构造函数。
  • 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化
  • 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才保证派生类对象先清理派生类成员再清理基类成员的顺序。

示意图如下:
在这里插入图片描述

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

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

相关文章

Elasticsearch:Jira 连接器教程第二部分 - 6 个优化技巧

作者&#xff1a;来自 Elastic Gustavo Llermaly 将 Jira 连接到 Elasticsearch 后&#xff0c;我们现在将回顾最佳实践以升级此部署。 在本系列的第一部分中&#xff0c;我们配置了 Jira 连接器并将对象索引到 Elasticsearch 中。在第二部分中&#xff0c;我们将回顾一些最佳实…

【狂热算法篇】探秘图论之 Floyd 算法:解锁最短路径的神秘密码(通俗易懂版)

&#xff1a; 羑悻的小杀马特.-CSDN博客羑悻的小杀马特.擅长C/C题海汇总,AI学习,c的不归之路,等方面的知识,羑悻的小杀马特.关注算法,c,c语言,青少年编程领域.https://blog.csdn.net/2401_82648291?spm1010.2135.3001.5343 在本篇文章中&#xff0c;博主将带大家去学习所谓的…

npm的包管理

从哪里下载包 国外有一家 IT 公司&#xff0c;叫做 npm,Inc.这家公司旗下有一个非常著名的网站: https://www.npmjs.com/&#xff0c;它是全球最大的包共享平台&#xff0c;你可以从这个网站上搜索到任何你需要的包&#xff0c;只要你有足够的耐心!到目前位置&#xff0c;全球约…

GitLab:添加SSH密钥之前,您不能通过SSH来拉取或推送项目代码

1、查看服务器是否配置过 [rootkingbal-ecs-7612 ~]# cd .ssh/ [rootkingbal-ecs-7612 .ssh]# ls authorized_keys id_ed25519 id_ed25519.pub id_rsa id_rsa.pub2、创建密钥 $ ssh-keygen -t rsa -C kingbalkingbal.com # -C 后写你的邮箱 一路回车 3、复制密钥 [rootk…

为ARM64架构移植Ubuntu20.04换源的发现

在为ARM64架构(RK3566)移植ubuntu20.04的时候发现在更换为国内源之后&#xff0c;无法正常完成apt update,报错为: Ign:25 http://mirrors.aliyun.com/ubuntu focal-updates/main arm64 Packages …

LARGE LANGUAGE MODELS ARE HUMAN-LEVEL PROMPT ENGINEERS

题目 大型语言模型是人类级别的提示工程师 论文地址&#xff1a;https://arxiv.org/abs/2211.01910 项目地址&#xff1a;https://github.com/keirp/automatic_prompt_engineer 摘要 通过对自然语言指令进行调节&#xff0c;大语言模型 (LLM) 显示了作为通用计算机的令人印象深…

Redisson发布订阅学习

介绍 Redisson 的消息订阅功能遵循 Redis 的发布/订阅模式&#xff0c;该模式包括以下几个核心概念&#xff1a; 发布者&#xff08;Publisher&#xff09;&#xff1a;发送消息到特定频道的客户端。在 Redis 中&#xff0c;这通过 PUBLISH 命令实现。 订阅者&#xff08;Sub…

git操作(Windows中GitHub)

使用git控制GitHub中的仓库版本&#xff0c;并在Windows桌面中创建与修改代码&#xff0c;与GitHub仓库进行同步。 创建自己的GitHub仓库 创建一个gen_code实验性仓库用来学习和验证git在Windows下的使用方法&#xff1a; gen_code仓库 注意&#xff0c;创建仓库时不要设置…

【tailscale 和 ssh】当服务器建立好节点,但通过客户端无法通过 ssh 连接

背景 当服务器建立好节点&#xff0c;一切显示正常但通过客户端无法通过 vs code 中的 ssh 连接到服务器 问题解决 因为服务器是重装过的&#xff0c;所以忘记在服务器上下载 ssh 了。。。安装完成并启动 SSH 服务后便可正常连接&#xff01; sudo apt update sudo apt in…

KubeSphere部署安装,接入KubeKey安装的k8s集群

KubeSphere安装接入KubeKey安装的k8s集群 文章目录 KubeSphere安装接入KubeKey安装的k8s集群 一.NFS安装配置1.服务器安装NFS服务2.下载并部署 NFS Subdir External Provisioner1).下载部署文件2).创建 NameSpace3).创建 RBAC 资源4).配置 deployment.yaml5).部署 Storage Clas…

基于智能物联网的肉鸡舍控制器:设计、实施、性能评估与优化

英文标题&#xff1a; Smart IoT-Based Broiler Room Controller: Design, Implementation, Performance Evaluation, and Optimization 作者信息 Shamsu Sabo Department of Computer Science, National Open University of Nigeria, Fagge Study Center, Nigeria Email: 144…

JavaScript-正则表达式方法(RegExp)

RegExp 对象用于将文本与一个模式匹配。 有两种方法可以创建一个 RegExp 对象&#xff1a;一种是字面量&#xff0c;另一种是构造函数。 字面量由斜杠 (/) 包围而不是引号包围。 构造函数的字符串参数由引号而不是斜杠包围。 new RegExp(pattern[, flags])一.符集合 1.选择…

【Flink系列】4. Flink运行时架构

4. Flink运行时架构 4.1 系统架构 Flink运行时架构——Standalone会话模式为例 1&#xff09;作业管理器&#xff08;JobManager&#xff09; JobManager是一个Flink集群中任务管理和调度的核心&#xff0c;是控制应用执行的主进程。也就是说&#xff0c;每个应用都应该被…

C#中无法在串口serialPort1_DataReceived启动定时器的解决方法

这里的串口名是serialPort1&#xff0c;定时器名是timerRxInterval 方法1——修改启动方法 private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) {Invoke((MethodInvoker)delegate { timerRxInterval.Start(); }); } private void timerRxI…

gateway worker 分布式

有三个文件start_register.php&#xff0c;start_gateway.php&#xff0c;start_businessworker.php&#xff0c; 一、start_register.php &#xff08;1&#xff09;是用于通讯的&#xff0c;注册地址的&#xff1b; 二、start_gateway.php &#xff08;1&#xff09;用于跟…

当当网书籍信息爬虫

1.基本理论 1.1概念体系 网络爬虫又称网络蜘蛛、网络蚂蚁、网络机器人等&#xff0c;可以按照我们设置的规则自动化爬取网络上的信息&#xff0c;这些规则被称为爬虫算法。是一种自动化程序&#xff0c;用于从互联网上抓取数据。爬虫通过模拟浏览器的行为&#xff0c;访问网页…

【数据分享】1929-2024年全球站点的逐月平均气温数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01;本次我们为大家带来的就是具体到气象监…

【鱼皮大佬API开放平台项目】Spring Cloud Gateway HTTPS 配置问题解决方案总结

问题背景 项目架构为前后端分离的微服务架构&#xff1a; 前端部署在 8000 端口API 网关部署在 9000 端口后端服务包括&#xff1a; api-backend (9001端口)api-interface (9002端口) 初始状态&#xff1a; 前端已配置 HTTPS&#xff08;端口 8000&#xff09;后端服务未配…

qml DirectionalBlur详解

1、概述 DirectionalBlur是QML&#xff08;Qt Modeling Language&#xff09;中用于创建方向模糊效果的一种图形效果类型。它通过对源图像的像素进行模糊处理&#xff0c;产生一种源项目朝着模糊方向移动的感知印象。这种模糊效果被应用到每个像素的两侧&#xff0c;因此设置方…

图像处理|闭运算

闭运算&#xff08;Closing&#xff09;是形态学操作中的另一种基本操作&#xff0c;它与开运算&#xff08;Opening&#xff09;类似&#xff0c;但执行的步骤相反。闭运算结合了膨胀和腐蚀操作&#xff0c;顺序为 先膨胀后腐蚀。这种操作通常用于填补图像中的小空洞&#xff…