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

一、单/多/菱形继承

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.hqwc.cn/news/223346.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rust内存布局

题图忘了来自哪里.. 整型,浮点型,struct,vec!,enum 本文是对 Rust内存布局 的学习与记录 struct A { a: i64, b: u64,}struct B { a: i32, b: u64,}struct C { a: i64, b: u64, c: i32,}struct D { a: i32, b: u64, c: i32, d: u64,}fn main(…

达索系统3DEXPERIENCE WORKS 2024电磁仿真功能

在设计工作中&#xff0c;将复杂的模型进行网格分割是必不可少的一步&#xff0c;这样可以化繁而简&#xff0c;也可以让后续的工作更容易开展。 电磁仿真可帮助您在复杂、嘈杂的电磁环境中提高效率&#xff0c;在确保兼容性的同时&#xff0c;保障出众性能。 一系列专用求解器…

MySQL(免密登录)

简介: MySQL免密登录是一种允许用户在没有输入密码的情况下直接登录到MySQL服务器的配置。这通常是通过在登录时跳过密码验证来实现的。 1、修改MySQL的配置文件 使用vi /etc/my.cnf&#xff0c;添加到【mysqld】后面 skip-grant-tables #配置项告诉mysql跳过权限验证&#…

论文阅读:“Model-based teeth reconstruction”

文章目录 AbstractIntroductionTeeth Prior ModelData PreparationParametric Teeth Model Teeth FittingTeeth Boundary Extraction Reference Abstract 近年来&#xff0c;基于图像的人脸重建方法日趋成熟。这些方法可以捕捉整个面部或面部特定区域&#xff08;如头发、眼睛…

Go 中切片(Slice)的长度与容量

切片长度与容量在 Go 中很常见。切片长度是切片中可用元素的数量&#xff0c;而切片容量是从切片中第一个元素开始计算的底层数组中的元素数量。 Go 中的开发者经常混淆切片长度和容量&#xff0c;或者对它们不够了解。理解这两个概念对于高效处理切片的核心操作&#xff0c;比…

Linux git

1.Git 初识 不知道你⼯作或学习时&#xff0c;有没有遇到这样的情况&#xff1a;我们在编写各种⽂档时&#xff0c;为了防止文档丢失&#xff0c;更改失误&#xff0c;失误后能恢复到原来的版本&#xff0c;不得不复制出⼀个副本&#xff0c;⽐如&#xff1a; “报告-v1”? …

带你用uniapp从零开发一个仿小米商场_10. 首页开发

图标菜单栏开发 轮播图开发完成后,就是图标菜单栏了 可以看出这些图标都是一样的样式,所以可以勇哥flex布局让他们每个占百分之20 代码如下,既然都是一样的那就直接用个循环嵌套一下 data数据如下 同样,为了能让这段代码能在别的地方也用到,我直接把它封装成组件 <templ…

多模态融合16篇优质论文及代码合集,含2023最新

多模态融合是多模态学习领域的基础问题&#xff0c;也是多模态研究中非常关键的研究点。它旨在从多个模态&#xff08;例如语音、图像、文本等&#xff09;中提取有价值的信息和特征&#xff0c;并将这些信息融合在一起以提高系统的性能。这一领域的研究内容广泛&#xff0c;包…

【Java并发】聊聊不安全的HashMap以及ConcurrentHashMap

在实际的开发中&#xff0c;hashmap是比较常用的数据结构&#xff0c;如果所开发的系统并发量不高&#xff0c;那么没有问题&#xff0c;但是一旦系统的并发量增加一倍&#xff0c;那么就可能出现不可控的系统问题&#xff0c;所以在平时的开发中&#xff0c;我们除了需要考虑正…

室内定位(WiFi/UWB/蓝牙等)技术方案概述

室内无法搜索到卫星&#xff0c;这样常规的GPS/北斗定位都无法使用&#xff0c;常规免费的只有运营商的基站定位LBS&#xff0c;但这个精度实在太差&#xff0c;一般都有几十米到几百米的偏差。因此&#xff0c;室内定位一直是个老大难问题。 截至目前&#xff0c;业界比较成熟…

【JMeter】运行方式

第一种&#xff1a; 使用GUI 操作&#xff1a; 在JMeter界面菜单导航上点击运行按钮 一般用作创建TestPlan和调试脚本增加java堆空间来满足测试环境 第二种&#xff1a;使用CLI(Command Line) 性能测试一般请求量比较大&#xff0c;为了节省资源 CLI参数用法&#xff1a; 字段…

使用char.js 柱形方式显示 一年12个月的最高气温与最低气温

<!DOCTYPE html> <html> <head><title>气温图表</title><script src"https://cdn.jsdelivr.net/npm/chart.js"></script><style>#myChart{width:800px;height: 400px;}</style> </head> <body>&l…