【C++】继承(下) 单继承 | 多继承 | 菱形继承 | 继承和组合

news2024/11/26 16:45:19

一、单/多/菱形继承

1.单继承

当一个子类只有一个直接父类时,称这个继承关系为单继承。

2.多继承

一个子类有两个或以上直接父类时称这个继承关系为多继承。

举个实例:新老师进学校工作时,一般会作为助教老师,一边代课教书,一边跟着经验足的老教师后头 学习一阵子。这时我们定义出的"Assistant"类,就同时具有老师、学生这两种属性。这就是多继承的思想。

多继承的书写格式为:逗号+继承方式+父类名

3.菱形继承

是多继承的一种特殊情况。

a.产生的问题

这种继承结构会导致二义性 以及空间浪费等问题。

什么叫产生二义性?我用上面的例子解释给你听:

class Person
{
public:
    Person(string str="")
        :_name(str)
    {}
    string _name="";
};
​
class Student : public Person  //继承了person
{
public:
    Student()
        :Person("student")
    {}
    int _num=0;
};
​
class Teacher : public Person   //继承了person
{
public:
    Teacher()
        :Person("teacher")
    {}
    int _id=0;
};
 
class Assistant :public Student, public Teacher   //继承的这俩,都是person的派生类
{};
int main() {
    Assistant a;
    cout << a._name << endl;
    return 0;
}

这样写,编译是无法通过的:

这是因为此时的a里面,有两个_name,编译器不知道用哪个了:

如果还是不理解,可以看这张图:

这就产生了二义性。并且,由于Assistant中有两份 _name的拷贝,当 _name要用的空间很大的话,就会造成空间浪费。

b.如何解决

那遇到菱形继承的情况,要怎么解决二义性和数据冗余的问题呢?

Way1. 显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决。

cout << a.Student::_name << endl;
cout << a.Teacher::_name << endl;

Way2. 虚拟继承

先来介绍下虚拟继承:虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类。

怎么设为虚继承呢?在继承方式前加上virtual关键字即可。

(注意:虚拟继承是专门用于处理 菱形继承 的手段,不要在其他地方去使用)

class Person
{
public:
    Person(string str="")
        :_name(str)
    {}
    string _name="";
};
​
class Student :virtual public Person   //虚继承
{
public:
    Student()
        :Person("student")
    {}
    int _num=0;
};
​
class Teacher :virtual public Person   //这俩都设为虚继承
{
public:
    Teacher()
        :Person("teacher")
    {}
    int _id=0;
};
​
class Assistant :public Student, public Teacher
{};
int main() {
    Assistant a;
    cout << a._name << endl;
    return 0;
}

这里编译器做了优化处理,看似有3个Person,实际上只有一个,这仨都是同一个:

虚继承使得从不同路径继承来的同名基类,在派生类中只产生一个实例,避免了二义性问题。

4.劝告

一般不建议设计出多继承,并且,如果不是迫不得已,不要设计出菱形继承!否则在复杂度及性能上容易出问题。

多继承可以认为是C++的缺陷之一,很多后来的语言都没有多继承,如Java。

二、继承和组合

继承与组合都是用于描述类之间的关联关系的。

继承:继承是一种"is-a"的关系,表示一个类从另一个类派生而来,每个派生类对象都是一个基类对象。

组合:组合是一种"has-a"的关系,表示一个类包含另一个类的对象作为成员变量。通过组合,一个类可以使用另一个类的功能,但不会继承其属性和方法。

在不同的情境下,俩类之间设为继承关系还是组合关系好呢?下面用例子来说明。

//继承
class Car{
    ……
};
​
class BMW : public Car{   //宝马is a car,这俩构成继承关系
    ……
};
//组合
class Tire{
    ……
};
​
class Car{   //car has a tire,这俩构成组合关系
    Tire _t;
    ……
};  

通过这俩例子,可见用继承还是组合,得去判断是"is a"还是"has a",如果前者,就用继承;后者就用组合;两个都行,那就优先用组合。优先使用组合,而不是继承。

这里说明下 优先用组合 的原因:

继承是一种白箱复用。所谓白箱复用,就是透明可视化的一种复用,父类的内部细节对子类可见。这在一定程度上破坏了父类的封装。

并且,父类和子类的依赖关系很强,耦合度很高。试想,假如父类的某个成员被修改了,那在所有的子类中也会遭到修改。

而组合是一种黑箱复用。黑箱复用是另一种复用风格:新的更复杂的功能可以通过组合对象来获得。这要求被组合的对象具有良好定义的接口。派生类直接拿接口来用,而不涉及它的内部实现,这保护了基类的封装性。

并且,耦合度低,代码维护性好,我修改基类的某个成员,子类并不会受影响。

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

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

相关文章

【shell】正则表达式和文本三剑客之grep和awk

目录 一、正则表达式 1.1用法 1.2表示字符匹配 1.3表示次数 1.4表示位置锚定 1.5表示分组或其他 1.6扩展正则表达式 二、grep命令 三、awk命令 3.1awk与vim的区别 3.2awk的语法 3.3基础用法 test1.提取磁盘的分区利用率 test2.提取用户名和uid号 test3.提取ip地址…

数据结构与算法编程题27

计算二叉树深度 #define _CRT_SECURE_NO_WARNINGS#include <iostream> using namespace std;typedef char ElemType; #define ERROR 0 #define OK 1 #define Maxsize 100 #define STR_SIZE 1024typedef struct BiTNode {ElemType data;BiTNode* lchild, * rchild; }BiTNo…

前端入职环境安装

前端入职 后环境安装 &#xff0c;内函 nodenvmgit微信开发者工具vscode 的安装包 一.node安装-js运行环境 1.node下载&#xff0c;下载地址Node.js 2.配置淘宝镜像 npm config set registry https://registry.npmmirror.com/ 3.查看配置 npm config list 二.nvm安装-切…

必应的下一个十年:穿越创新的奇点时刻

2023年是微软搜索引擎必应进入中国市场十周年&#xff0c;2024年也将迎来必应上市十五周年。对于风起云涌的互联网公司来说&#xff0c;十年到十五年是一个相当长的创新周期。而在2023年初&#xff0c;以GPT为代表的大语言模型横扫全球科技产业&#xff0c;也对互联网和云计算带…

力扣刷题篇之递归

系列文章目录 目录 系列文章目录 前言 一、二叉树相关问题 二、回溯相关问题 三、动态规划相关问题 总结 前言 刷题按照&#xff1a;[力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 - 力扣&#xff08;LeetCode&#xff09;&#xff0c;如图&#xff0c;因为是讲…

pytorch实现遥感建筑物提取

如何自动地从高分辨率遥感影像中提取建筑物等人工目标是高分辨率遥感影像处理与理解领域的一个热点与难点问题。本篇文章我们将学习如何使用pytorch实现遥感建筑物的智能提取。 智能提取的流程 基于深度学习的遥感建筑物智能提取&#xff0c;首先需要制作数据集&#xff0c;然后…

抽象类的使用—模板设计模式 Java

模板设计模式 一、引入二、改进 一、引入 需求 ① 有多个类&#xff0c;完成不同的任务 job ② 要求统计得到各自完成任务的时间 ③ 请编程实现 >最容易想到的方法&#xff0c;写类&#xff0c;统计时间 AA BB中的 job 方法中是有重复的。 >改进1&#xff1a;每个类中&…

使用conan包 - 安装依赖项

使用conan包 - 安装依赖项 主目录 conan Using packages1 Requires2 Optional user/channel3 Overriding requirements4 Generators5 Options 本文是基于对conan官方文档Installing dependencies的翻译而来&#xff0c; 更详细的信息可以去查阅conan官方文档。 This section s…

Vue简易的车牌输入键盘,可以根据需要修改

效果图如下&#xff1a; 代码如下&#xff1a; <template><div><div class"carNoBoxInput"><div style"padding: 6px;border: 2px solid #fff;border-radius: 6px;margin: 6px 3px 6px 6px;"><input class"inputBox"…

避免手机无节制使用

手机使用情况分析 使用时间 我挑选了11月份某一周的统计数据&#xff0c;可以看到&#xff0c;我的日均手机手机时间达到了惊人的8个小时&#xff0c;每周总共余约57小时。 按照使用软件的类型来分类&#xff0c;其中约%50用于娱乐&#xff0c;主要使用软件为&#xff1a;哔哩…

[SpringCloud] SpringCloud配置中心的核心原理

SpringCloud是什么时候去拉取配置中心的配置中心客户端的配置信息为什么要写在bootstrap文件中对象中注入的属性是如何动态刷新的一些开源的配置中心是如何整合SpringCloud的 文章目录 1.从SpringBoot的启动过程说起1.1 大致过程 2.准备Environment的核心操作2.1 前置操作 3.pr…

每日一题:LeetCode-202.快乐数(一点都不快乐)

每日一题系列&#xff08;day 06&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

【数据结构】图<简单认识图>

对于下面的内容&#xff0c;大家着重观察和理解图即可&#xff0c;可以直接绕过一些文字性的概念&#xff0c;对图有一个大概的认识。 图 简单认识图图的定义有向图和无向图完全图无向完全图有向完全图 图的基本存储结构邻接矩阵存储邻接矩阵的优点 网络的邻接矩阵邻接表无向图…

C++基础 -5- 动态内存分配

相对于c语言的优势 C可以在分配空间时初始化 返回的内存地址不需要进行强制类型转换 动态申请单块内存格式(图片代码段呈现) 且在分配的时候可以用圆括号直接赋值 int *bnew int(99);动态申请多块内存格式 int *anew int[1024]{88,99,1010};释放空间 释放单块 delete b;释放…

centos7 keepalived探测当前节点

手动查看 查看keepalived集群主节点在哪台服务器&#xff0c;执行命令&#xff1a; ip a 看下自己设定的虚IP在哪台服务器&#xff0c;哪台就是主节点。 脚本实现 rm -rf ./tmp.log ip a > ./tmp.log if cat tmp.log |grep "132" thenecho -e "\033[32m…

香港科技大学广州|智能制造学域博士招生宣讲会—天津大学专场

时间&#xff1a;2023年12月07日&#xff08;星期四&#xff09;15:30 地点&#xff1a;天津大学卫津路校区26楼B112 报名链接&#xff1a;https://www.wjx.top/vm/mmukLPC.aspx# 宣讲嘉宾&#xff1a; 汤凯教授 学域主任 https://facultyprofiles.hkust-gz.edu.cn/faculty-p…

P19 C++ 构造函数的成员初始化列表

目录 前言 01 如果不用成员列表如何初始化变量 02 成员列表初始化 03 为什么要使用成员列表初始化呢&#xff1f; 04 案例代码 前言 本期我们聊聊构造函数初始化列表。 你应该经常使用成员初始化列表&#xff0c;如果你不喜欢这种代码风格&#xff0c;建议你还是慢慢习惯吧…

适配rem自动转换插件(vscode)

可以根据自己的草稿图&#xff0c;设置自己想要多少px对应1rem 这样子在我们写css单位的时候就会自动转换为rem单位了&#xff0c;当然&#xff0c;转换肯定是可选的&#xff0c;不是说只能写rem了。

线程基本方法

1。设置线程名 继承Thread类的线程&#xff0c;可以直接使用.setName()方法&#xff0c;设置线程名。也可以使用构造方法&#xff0c;需要注意java默认不继承构造方法&#xff0c;所以需要自己调用下父类的构造方法。 public class Demo {public static void main(String[…

如何在手机上打开电脑端本地的网页

目录 一.手机端预览VSCode生成的网页站点二.手机端预览VS2022生成的 WebApi网页站点三.总结 今天遇到了2个小问题&#xff1a;1.想在手机上运行VSCode上写好的网页代码。2.同样在手机上运行VS2022 WebApi生成的网页。查找了一晚上资料&#xff0c;终于动手解决了&#xff0c;记…