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

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

  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"; 
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

无线领夹麦克风可以唱歌吗?推荐多款收音好的无线麦克风

如今是一个短视频营销飞速发展的时代&#xff0c;越来越多自媒体人通过短视频的方式来进行直播带货、生活Vlog、线上K歌等&#xff0c;记录下生活里那美丽的瞬间。不过也有不少新手视频创作者存在疑问&#xff1a;无线领夹麦克风可以唱歌吗&#xff1f; 答案是可以的&#xff0…

前端技术(二)——javasctipt 介绍

一、javascript基础 1. javascript简介 ⑴ javascript的起源 ⑵ javascript 简史 ⑶ javascript发展的时间线 ⑷ javascript的实现 ⑸ js第一个代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>…

SSM“点点通”餐饮点餐小程序-计算机毕业设计源码11264

摘要 随着中国经济的飞速增长&#xff0c;消费者的智能化水平不断提高&#xff0c;许多智能手机和相关的软件正在得到更多的关注和支持。其中&#xff0c;微信的餐饮点餐小程序更是深得消费者的喜爱&#xff0c;它的出现极大地改善了消费者的生活质量&#xff0c;同时&#xf…

电商价格监测:品牌控价维权的关键利器

品牌在进行控价时&#xff0c;所面对的是线上成千上万条的商品链接&#xff0c;如果仅依靠人工&#xff0c;根本无法做到准确且全面地完成电商价格监测工作。因此&#xff0c;一套准确率高的电商价格监测系统对于品牌的控价维权而言&#xff0c;其重要性不言而喻。 在形形色色的…

昇思25天学习打卡营第八天|保存与加载

背景 提供免费算力支持&#xff0c;有交流群有值班教师答疑的华为昇思训练营进入第八天了。 今天是第八天&#xff0c;前七天的学习内容可以看链接 昇思25天学习打卡营第一天|快速入门 昇思25天学习打卡营第二天|张量 Tensor 昇思25天学习打卡营第三天|数据集Dataset 昇思25天…

GPT-5:下一代AI如何彻底改变我们的未来

GPT-5 发布前瞻&#xff1a;技术突破与未来展望 随着科技的飞速发展&#xff0c;人工智能领域不断迎来新的突破。根据最新消息&#xff0c;OpenAI 的首席技术官米拉穆拉蒂在一次采访中确认&#xff0c;GPT-5 将在一年半后发布&#xff0c;并描述了其从 GPT-4 到 GPT-5 的飞跃如…

分布式限流:Spring Cloud Gateway 限流

分布式限流&#xff1a;Spring Cloud Gateway 限流 在现代微服务架构中&#xff0c;流量控制是一个至关重要的部分。分布式限流作为一种有效的流量控制手段&#xff0c;能够帮助我们保护系统不被突发的流量冲垮。Spring Cloud Gateway支持多种限流方式。 什么是分布式限流 分…

嵌入式UI开发-lvgl+wsl2+vscode系列:8、控件(Widgets)(一)

一、前言 这里将介绍一系列控件&#xff0c;了解后就可以开始基础的开发了。 二、示例 1、Base Obj&#xff08;基础对象&#xff09; 1.1、示例1 #include "../../lv_examples.h" #if LV_BUILD_EXAMPLESvoid lv_example_obj_1(void) {lv_obj_t * obj1;obj1 lv…

商城积分系统的代码实现(下)-- 积分订单的退款与结算

一、接着上文 用户在消耗积分的时候&#xff0c;需要根据一定的逻辑&#xff0c;除了扣减账户的当前余额&#xff0c;还需要依次消费积分订单的余额。 private void updatePointsOrderByUse(Integer schoolId, Long userId, String pointsType, int usingPoints) {List<Po…

springboot+vue 开发记录(八) 前端项目打包

本篇文章涉及到前端项目打包的一些说明 我打包后的项目在部署到服务器上后&#xff0c;访问页面时按下F12出现了这种情况&#xff1a; 它显示出了我的源码&#xff0c;这是一种很不安全的行为 该怎么办&#xff1f;很简单&#xff1a; 我们只需要下载一点点插件&#xff0c;再…

怎样查看vsphere client 的登录日志

- 问题摘要&#xff1a; 怎样查看vsphere client 的登录日志 - 解决方案/工作方法 1.登录vsphere client > vc > Monitor > Tasks and Events > Events, 查看日志 2. 查看VC 的websso.log日志 /var/log/vmware/sso/websso.log 3. 可以把websso.log文件拿到本地电…

苏东坡传-读书笔记六

苏东坡今生的浩然之气用尽。人的生活也就是心灵的生活&#xff0c;这种力量形成人的事业人品&#xff0c;与生命俱来&#xff0c;由生活中之遭遇而显示其形态。正如苏东坡在潮州韩文公庙碑中所说&#xff1a;“浩然之气、不依形而立&#xff0c;不恃力而行&#xff0c;不待生而…

智能驾驶系列报告:特斯拉智能驾驶方案简剖

不同于绝大多数国内车企在自动驾驶上采取多传感器融合方案&#xff0c;特斯拉FSD在发展初期就摒弃激光雷达、且不配备高清地图&#xff0c;成为在感知层以摄像头为核心的纯视觉解决方案代表;其依靠车身搭载的摄像头来捕捉周围的环境信息&#xff0c;并经过算法及神经网络模型处…

手机ip地址是实时位置吗

在数字时代&#xff0c;手机IP地址对于许多用户而言&#xff0c;似乎是一个既神秘又重要的存在。不少人都曾听说过&#xff0c;通过追踪IP地址可以定位到某个人的大致位置。那么&#xff0c;手机IP地址真的是实时位置的精确反映吗&#xff1f;本文将带您深入了解手机IP地址的真…

「网站开发必备」8款免费 React Gallery, Lightbox, 和 Photo Viewer开发库

大家好&#xff0c;今天给大家分8款免费 React Gallery, Lightbox, 和 Photo Viewer开发库。 在不断发展的网络开发世界中&#xff0c;开源库提供了大量创新和效率的机会。本文将带您了解一些用于Gallery, Lightbox, 和 Photo Viewer的最好的开源 React 库&#xff0c;为您的下…

2.00004 优化器执行计划生成的流程是怎么样的?

文章目录 整体架构关键结构体PlannerInfo (pathnodes.h:195)PlannerGlobal (pathnodes.h:95)函数栈关键函数pg_plan_query (postgres.c:885)planner (planner.c:274)standard_planner (planner.c:287)subquery_planner (planner.c:628)整体架构 关键结构体 PlannerInfo (pathn…

基于CST2024 Python内部环境的双锥天线自动3D建模和仿真

CST Studio Suite 2024版里面的Python相较于之前有了大的变化。 第一&#xff0c; 增加了cst.asymptotic &#xff0c;cst.radar &#xff0c;cst.units 三个包。 第二&#xff0c;之前CST python只能通过外部环境去操作&#xff0c;现在增加了内部环境控制&#xff0c;可以内…

Zabbix对接Elasticsearch(ES)数据库(未成功)

0.需求分析 不管zabbix的后端数据库是oracle还是mysql&#xff0c;当zabbix监控的量级达到了一定程度后&#xff0c;那么对数据库的性能是一个非常严峻的挑战。特别是对历史数据的查询&#xff0c;将会变得非常非常的慢&#xff0c;别告诉我可以建索引优化&#xff0c;当量级达…

8.12 矢量图层面要素单一符号使用十二(插值线渲染边界)

文章目录 前言插值线渲染边界&#xff08;Outline: Interpolated Line&#xff09;QGis设置面符号为插值线渲染边界&#xff08;Outline: Interpolated Line&#xff09;二次开发代码实现插值线渲染边界&#xff08;Outline: Interpolated Line&#xff09; 总结 前言 本章介绍…

C++ STL unique_ptr智能指针源码剖析

由于上一篇博客将shared_ptr,weak_ptr,enable_shared_form_this的源码实现整理了一遍,想着cpp智能指针还差个unique_ptr故写下此篇博客,以供学习 源码剖析 一,模板参数 首先,我们先看unique_ptr的模板参数,第一个参数_TP自是不用说表示对象类型,第二个模板参数定义了unique_p…