C++感受12-Hello Object 派生版

news2024/11/20 4:45:07

不变的功能,希望直接复用原有代码;变化的功能,希望在分开的代码里实现。

  1. 派生的基本概念和目的
  2. 如何定义派生类以及创建派生对象
  3. 派生对象的生死过程 

0. 课堂视频

ff14-HelloObject-派生版

1. 派生的基本概念与目的

编程,或者说软件系统的设计与实现的主要工作和最大痛苦来源,就是:变化。由于要面对变化,于是产生了许多程序设计思想、原则或方法,派生正是其中之一。

1.1 变与不变的代码原则

写程序时,很多时候,会发现当前地方需要用到的功能,在之前的某个地方,已经实现过一回了;又有很多时候,会发现,当前需要在原来的功能上,实现一些新的功能。这时候,一条基本且重要的原则出现了:

需要用到一样的功能,我们希望直接复用原有代码,而不是重新写一遍(哪怕你有复制粘贴大法);而当需要写不一样的功能时,我们希望新功能和旧功能能够在分开的代码中写,而不是混在一起写。

这个原则很好理解:

  1. 实现同样功能的代码如果到处出现,不仅费时费事,而且将来功能有变动时,就得到处修改;
  2. 同一段代码,却包含了多种不同逻辑的实现,表现看起来非常强大,但一来整体逻辑变得很复杂,并且非常容易写错。

派生就可以同时满足以上两点要求的一种编程方法(归在“面向对象”的编程思想中)。

课堂讲到的,实现“区分对待女神与普通人的自我介绍功能” 的 “if/else” 和 派生方案的对比,目的就是为了让同学通过实例,体会、理解到这个原则所能发挥的作用,以及发挥作用的方法。

一句话:在新的类型定义(当前我们学习了如何定义 struct )中实现新功能,从而保证“新功能和旧功能分开写”;而又能同时复用(继承)原有类型的原有功能。在这段话的描述中,新的类型就是派生类(derived-class),旧的类型叫基类(base-class)。

基类和派生类之间,可以称为 “派生 / derive ”,另一种常用的说法是“继承 / inherit”。当我们说“继承”时,通常是在强调新的类型从旧的类型身上复用(继承)了原有的功能;而当我们说“派生”时,则通常是在强调新的类型将在旧的类型的基础上,扩展(派生)了一些新的功能。两种说法是同一硬币的两个面,关系紧密,比如派生新功能时所用到的基础,往往就是继承自基类的原有方法或数据。

跨越语法的,通常用以下图形表示类型和类型之派生关系:

继承关系

阅读笔记

1.2 变与不变的具体例子

这是我们在上一节课 《Hello Object 成员版》 写的一段代码:

// 定义人类结构 
struct Person 
{ 
    Person() { std::cout << "哇哇~" << std::endl; }; 
    ~Person() { std::cout << "呜呜~" << std::endl; } 

    // 自我介绍 
    void Introduce() // 成员函数,方法 
    { 
        std::cout << "大家好,我叫 " << name << std::endl; 
    }  

    std::string name; // 成员数据,属性 
}; 

新需求是:美女能够有不同的自我介绍方式,但美女的生死过程要和普通人类(Person)一样地会“哇哇”或“呜呜”。

当然可以借助 if/else 来实现,只需要在原来就有的 Introduce () “动刀”:

void Introduce()
{
    if (name == "志玲")
    {
        // 在此处实现女神特有的自我介绍
    }
    else
    {
        std::cout << "大家好,我叫 " << name << std::endl;
    }
}

这种实现方法,除了用名字来判断一个人的外貌这一固有的“原罪”之外,还有个问题:不符合我们前面谈的基本原则中的第二个要求:新旧功能分开写。

3. 派生的基本语法

3.1 定义派生类

以我们熟悉的 struct (用户自定义类型方法之一)为例:

struct 派生类 : public 基类 
{ 
};

C++ 支持多种派生方法,比如私有派生和公有派生,其中公有派生最常用。上面示例代码中的 关键字 “public” 即指明这是一个公有派生关系。

当派生类是 struct 时,此处省略 public 也同样表示公有派生。

给个具体例子:美女类(Beauty)派生了(继承自)普通人类(Person)。

struct Beauty : public Person 
{ 
}; 

此时,表面上看,Beauty 结构中间空空,一无所有,但其实它已经拥有了继承自基类的成员数据 name 和 成员方法 Introduce() 。

依据需求,美女类将拥有自己的自我介绍方法:

struct Beauty : public Person
{
    void Introduce() 
    { 
       cout << "大家好,我是美女" << name << ",想得到大家的多多关照哦~" << endl; 
    }
};

注意,派生类的 Introduce() 方法的原型(函数三要素:名字、返回值、入参列表)和基类的完全一样,但实现改变了(更嗲一点?)。可以放心的是,两个版本不会打架。基类的对象使用基类的,派生类的对象使用派生类的。

这里讲的就是之前课程提到的“类型即约束”。基类类型约束基类对象,派生类类型约束派生类对象,各自安生……直到下一节课,有些对象会突然醒悟,发出 “王侯将相,宁有种乎”的呐喊……

可能你已经注意到了,Beauty 确实非常直接地使用到了 name ——如前所述,它继承自基类。

更需要注意到的是:Beauty 类完全没手写的构造函数和析构函数。在此情况下,依照 C++ 语言标准,编译器会自动为它生成有默认行为的构造和析构函数,并且(重点)二者的默认行为中,包括了各自去调用基类的版本。即:

  • 派生类默认的构造函数,会自动调用基类的构造函数;
  • 派生类默认的析构函数,会自动调用基类的析构函数。

所以,尽管什么也没写,但我们在构造一个 Beauty 的对象时,它会输出 “哇哇~”,而它在释放时,也将输出 “呜呜~”。

3.2 定义派生类对象

派生类也是类,所以还是通过类型定义一个对象(变量)的那一套,我们同样给出栈对象和堆对象的例子:

/* 此处是基类 Person 和 派生类 Beauty 的类定义,略 */ 
int main()
{
    Beauty b1;
    b1.Introduce();
    Beauty *b2 = new Beauty(); // 或 new Beauty b2->Introduce(); delete b2;
}

3.3 完整代码


#include <iostream>
#include <string>

// 基类
struct Person
{
    Person() { std::cout << "哇哇~" << std::endl; }

    ~Person() { std::cout << "呜呜~" << std::endl; }

    // 自我介绍 
    void Introduce() // 成员函数,方法 
    { 
       std::cout << "大家好,我叫 " << name << std::endl; 
    }

    std::string name; // 成员数据,属性
};

// 派生类 
struct Beauty : public Person
{
    void Introduce() 
    { 
        cout << "大家好,我是美女" 
             << name << ",想得到大家的多多关照哦~" << endl; 
    }
};

int main()
{
    Person xiaoA; // 变量小A,普通人类 
    xiaoA.name = "小A";
    
    Person 如花; // 小心出现中文符号 
    如花.name = "如花";
    
    Beauty zhiLing;
    zhiLing.name = "王钢蛋";
    
    auto* jiaLing = new Beauty;
    jiaLing->name = "嘉铃"; // 我更喜欢 “加0”
    
    xiaoA.Introduce();
    如花.Introduce();
    zhiLing.Introduce();
    jiaLing->Introduce();
    
    delete jiaLing;
}

为什么非要有个堆变量呢?因为下节要用啊,好怕同学们才隔一节课就忘记了。

4. 派生对象的生死过程

4.1 多级构造与析构过程

  • 派生对象构造时,先调用基类的构造函数,再调用自己的构造过程;
  • 派生对象析构时,先调用自己的析构函数,再调用基类的析构过程。

如果把基类比成一楼,派生类比成二楼,那就是:

  • 构造就是盖楼,先盖一楼,再盖二楼;
  • 析构就是拆楼,先拆二楼,再盖二楼。

如果还有三楼、四楼,整个过程依次延顺。

注意,画楼层时,通常二楼在上,一楼在下。但画派生关系图时,基类在下,派生类在上,且箭头是从派生指向基类。

4.2 示例程序

关于派生类构造也析构的完整测试代码:

#include <iostream>

using namespace std; // 间接限定 s

truct ShaFaTie // 沙发贴,“爷爷类” 
{ 
   ShaFaTie() { cout << "哈哈,捡到沙发,笑抚二楼狗头。" << endl; }
   ~ShaFaTie() { cout << "我是一楼,结贴。" << endl; } 
}; 

struct BanDengTie : public ShaFaTie // 板凳贴,“爸爸类” 
{ 
    BanDengTie() { cout << "[回复] 抢到板凳。一楼你好舒服!笑看三楼躺地板。" << endl; } 
    ~BanDengTie() { cout << "我是二楼,结贴。" << endl; } 
}; 

struct DiBanTie : public BanDengTie // 地板贴,“孙子类” 
{ 
    DiBanTie() { cout << "[回复] 三楼怎么啦?席地而坐,凸显不同。" << endl; } 
    ~DiBanTie() { cout << "我是三楼,结贴。" << endl; } 
}; 

int main() 
{ 
   ShaFaTie l1; 
   cout << "===============\n"; 
   
   BanDengTie l2; 
   cout << "===============\n"; 

   DiBanTie l3; 
   cout << "===============\n"; 
}

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

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

相关文章

Games101学习笔记 Lecture 14: Ray Tracing 2 (Acceleration Radiometry)

Lecture 14: Ray Tracing 2 (Acceleration & Radiometry 一、加速光线追踪 AABB1.均匀网格 Uniform Spatial Partitions (Grids)①前处理-构建加速网格②射线与场景相交③网格分辨率④适用情况 2.空间划分KD-Tree①预处理②数据结构③遍历④问题 3.对象划分 & 包围盒层…

使用Python绘制极坐标图

使用Python绘制极坐标图 极坐标图极坐标图的优点使用场景 效果代码 极坐标图 极坐标图&#xff08;Polar Chart&#xff09;是一种图表类型&#xff0c;用于显示在极坐标系中的数据。极坐标图使用圆形坐标系&#xff0c;角度表示一个变量的值&#xff0c;半径表示另一个变量的…

森马基于MaxCompute+Hologres+DataWorks构建数据中台

讲师&#xff1a;晋银龙 浙江森马数仓高级经理 本次案例主要分享森马集团面对多年自建的多套数仓产品体系&#xff0c;通过阿里云MaxComputeHologresDataWorks统一数仓平台&#xff0c;保障数据生产稳定性与数据质量&#xff0c;减少ETL链路及计算时间&#xff0c;每年数仓整体…

Vue中的axios深度探索:从基础安装到高级功能应用的全面指南

文章目录 前言一、axios 请求1. axios的概念2. axios的安装3. axiso请求方式介绍4. axios请求本地数据5. axios跨域6. axios全局注册7. axios支持的请求类型1&#xff09;get请求2&#xff09;post请求3&#xff09;put请求4&#xff09;patch请求5&#xff09;delete请求 二、…

K8s的基本使用和认识

目录 介绍 控制端 Node(节点) 控制端与节点的关系图 基本使用 创建和运行资源 查找和参看资源 修改和删除资源 介绍 控制端 api-server(api)是集群的核心是k8s中最重要的组件,因为它是实现声明式api的关键 kubernetes api-server的核心功能是提供了Kubernetes各类资…

基于FreeRTOS+STM32CubeMX+LCD1602+MCP3008(SPI接口)的ADC转换器Proteus仿真

一、仿真原理图: 二、运行效果: 三、STM32CubeMX配置: 1)、RCC配置: 2)、SPI配置: 四、部分代码: 1)、主函数: /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main…

mysql8.0.19安装zip版本

下载地址https://downloads.mysql.com/archives/community/ 下载版本 下载后解压&#xff0c;不包括data 和my.ini文件。其中data 文件是自动生成的【mysqld --initialize --console】&#xff0c;my.ini需要自己编写设置。 新建my.ini文件 需要自己设置 basedirG:\soft\mysql…

华为DCN网络之:VXLAN

VXLAN RFC定义了VLAN扩展方案VXLAN&#xff08;Virtual eXtensible Local Area Network&#xff0c;虚拟扩展局域网&#xff09;。VXLAN采用MAC in UDP封装方式&#xff0c;是NVO3&#xff08;Network Virtualization over Layer 3&#xff09;中的一种网络虚拟化技术。 VXLAN…

android studio 添加aar包

按着以前旧的导包方式栽了大跟头&#xff0c;后面在留老板的的博客下找到了解决办法&#xff0c;记录一下。 Andriod Studio 导入aar最新的方式_gradle 8 引入arr-CSDN博客 最新导包方式 1.在新建libs目录&#xff0c;在app/libs目录下导入aar包&#xff08;其实就是拷贝过去…

hive4 从入门到精通

查询hive 架构 准备 HDFS配置 vim $HADOOP_HOME/etc/hadoop/core-site.xml <!--配置所有节点的root用户都可作为代理用户--><property><name>hadoop.proxyuser.root.hosts</name><value>*</value></property><!--配置root用户…

ETH巨鲸鱼异动和最大BTC爆仓

小编使用币界网地址监控工具&#xff0c;跟踪了在一次令人震惊的链上巨鲸地址异动&#xff0c;一个新创建的地址在过去四个小时内从 Coinbase 提取了价值 2121 万美元的 ETH。总共积累了 6,215 个 ETH&#xff0c;平均购买价格为每 ETH 3,414 美元。如此大规模的提款暗示着周一…

JVM原理(八):JVM虚拟机工具之基础故障工具

这里主要介绍监视虚拟机运行状态和进行故障处理的工具 1. jsp:虚拟机进程状况工具 jsp命令格式&#xff1a; jsp [options] [hostid] jps远程查询虚拟机进程状态 2. jstat:虚拟机统计信息监视工具 jstat命令格式&#xff1a; jstat [option vmid [interval [s|ms] [count]…

【Elasticsearch】Elasticsearch索引创建与管理详解

文章目录 &#x1f4d1;引言一、Elasticsearch 索引的基础概念二、创建索引2.1 使用默认设置创建索引2.2 自定义设置创建索引2.3 创建索引并设置映射 三、索引模板3.1 创建索引模板3.2 使用索引模板创建索引 四、管理索引4.1 查看索引4.2 更新索引设置4.3 删除索引 五、索引别名…

基于VUE3+VITE+SpringBoot+Nginx部署项目之跨域配置等问题

前言&#xff1a;遇到问题&#xff0c;解决问题。 第一部分&#xff1a;VUE 配置 1、vite.config.js 文件 server: {proxy: {/api: {target: env.VITE_BASE_URL,changeOrigin: true,secure: false,rewrite: path > path.replace(/^\/api/, )}}}, 2、.env 文件 VITE_BAS…

Tampermonkey 油猴脚本使用教程

Tampermonkey 油猴脚本使用教程 一、Tampermonkey 油猴脚本简介 Tampermonkey 是一款流行的浏览器扩展&#xff0c;它允许用户通过用户脚本增强网页功能或改变网页的外观。它支持包括 Chrome、Microsoft Edge、Safari、Opera Next 和 Firefox 在内的多种浏览器。Tampermonkey…

搭建LNMP环境实现高并发请求

LNMP和Nginx详细配置 一、LNMP环境平台搭建准备工作源码软件包安装nginxmysqlphp使用nginx连接php 二、web服务器-nginx1.学nginx之前需要了解的知识1.1 同步和异步&#xff08;通知结果的方式&#xff09;1.2 阻塞和非阻塞&#xff08;进线程等待时状态&#xff09;1.3 epoll模…

.NET 漏洞情报 | 某整合管理平台SQL注入

01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xf…

Github 2024-07-01开源项目月报 Top15

根据Github Trendings的统计,本月(2024-07-01统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目6JavaScript项目3C++项目2PHP项目1Blade项目1非开发语言项目1C#项目1Lua项目1Go项目1MDX项目1Jupyter Notebook项目1从零开始构建你喜…

AI绘画:探索人工智能与艺术的奇妙结合

前言 人工智能技术的不断发展&#xff0c;使得AI绘画逐渐成为艺术领域的新宠。AI绘画是指利用人工智能算法进行绘画创作的一种艺术形式&#xff0c;它可以模拟人类艺术家的创作过程&#xff0c;创造出各种独特的艺术作品。 突破传统艺术的极限&#xff1a;AI绘画的无限可能性 …

学习CAN协议(二):使用CAN发送数据

相关文章 学习CAN协议&#xff08;一&#xff09;&#xff1a;CAN协议简介 学习CAN协议&#xff08;二&#xff09;&#xff1a;使用CAN发送数据 学习CAN协议&#xff08;三&#xff09;&#xff1a;使用CAN接收数据 目录 一、配置CubeMX 二、代码编写 CAN的发送示例代码…