C++:组合和继承的区别

组合介绍以及与继承对比

什么是组合
(1)composition,组合,就是在一个class内使用其他多个class的对象作为成员
(2)用class tree做案例讲解
(3)组合也是一种代码复用方法,本质也是结构体包含

#include <iostream>
#include <vector>
#include <string>// Leaf 类
class Leaf {
public:Leaf(const std::string& color) : color_(color) {std::cout << "Leaf constructor called: " << color_ << std::endl;}~Leaf() {std::cout << "Leaf destructor called: " << color_ << std::endl;}void display() const {std::cout << "Leaf color: " << color_ << std::endl;}private:std::string color_;
};// Branch 类
class Branch {
public:Branch(int length) : length_(length) {std::cout << "Branch constructor called: " << length_ << " cm" << std::endl;}~Branch() {std::cout << "Branch destructor called: " << length_ << " cm" << std::endl;}void display() const {std::cout << "Branch length: " << length_ << " cm" << std::endl;}private:int length_;
};// Tree 类,包含 Leaf 和 Branch 对象
class Tree {
public:Tree(const std::string& leafColor, int branchLength) : leaf_(leafColor), branch_(branchLength) {std::cout << "Tree constructor called" << std::endl;}~Tree() {std::cout << "Tree destructor called" << std::endl;}void display() const {leaf_.display();branch_.display();}private:Leaf leaf_;Branch branch_;
};int main() {Tree tree("Green", 150);tree.display();return 0;
}

在这里插入图片描述

继承与组合的特点对比
(1)继承是a kind of(is a)关系,具有传递性,不具有对称性。
(2)组合是a part of(has a)的关系,
(3)继承是白盒复用。因为类继承允许我们根据自己的实现来覆盖重写父类的实现细节,父类的实现对于子类是可见的。
(4)继承的白盒复用特点,一定程度上破坏了类的封装特性,因为这会将父类的实现细节暴露给子类
(5)组合属于黑盒复用。被包含对象的内部细节对外是不可见的,所以它的封装性相对较好,实现上相互依赖比较小
(6)组合中被包含类会随着包含类创建而创建,消亡而消亡。组合属于黑盒复用,并且可以通过获取其它具有相同类型的对象引用或指针,在运行期间动态的定义组合。而缺点就是致使系统中的对象过多。
(7)OO设计原则是优先组合,而后继承

多继承及其二义性问题

多继承
(1)多继承就是一个子类有多个父类
(2)多继承演示
(3)多继承和单继承的原理,效果并无明显区别
(4)多继承会导致二义性问题
多继承的二义性问题1
(1)场景:C多继承自A和B,则C中调用A和B的同名成员时会有二义性
(2)原因:C从A和B各自继承了一个同名(不同namespace域)成员,所以用C的对象来调用时编译器无法确定我们想调用的是哪一个
(3)解决办法1:避免出现,让A和B的public成员命名不要重复冲突。但这个有时不可控。
(4)解决办法2:编码时明确指定要调用哪一个,用c.A::func()明确指定调用的是class A的func而不是class B的
(5)解决办法3:在C中重定义func,则调用时会调用C中的func,A和B中的都被隐藏了
(6)总结:能解决,但是都没有很好的解决。

多继承的二义性问题2
(1)场景:菱形继承问题。即A为祖类,B1:A, B2:A, C:B1,B2,此时用C的对象调用A中的某个方法时会有二义性
(2)分析:c.func()有二义性,c.A::func()也有二义性,但是c.B1::func()和c.B2::func()却没有二义性
(3)解决办法:和问题1中的一样,但是问题2更隐蔽,也更难以避免

在这里插入图片描述

// 祖类
class Aa {public:void show() { std::cout << "A's method" << std::endl; }
};// 派生类 B1 和 B2,从 A 继承
class B1 : public Aa {public:void show() { std::cout << "B1's show" << std::endl; }void showB1() { std::cout << "B1's method" << std::endl; }
};class B2 : public Aa {public:void show() { std::cout << "B2's show" << std::endl; }void showB2() { std::cout << "B2's method" << std::endl; }
};// 派生类 C,从 B1 和 B2 继承
class C : public B1, public B2 {public:void showC() { std::cout << "C's method" << std::endl; }
};int test070103() {C c;// c.Aa::show();    // 调用 A 的方法 不可以c.Aa::B1::show();  // 调用 A 的方法 不可以c.B2::Aa::show();  // 调用 A 的方法 不可以c.B1::show();      // 调用 B1 的方法c.B2::show();      // 调用 B2 的方法c.showB1();        // 调用 B1 的方法c.showB2();        // 调用 B2 的方法c.showC();         // 调用 C 的方法return 0;
}

虚继承解决菱形继承的二义性问题

虚继承怎么用
(1)场景:菱形继承导致二义性问题,本质上是在孙子类C中有B1和B2中包含的2份A对象,所以有了二义性。
(2)虚继承解决方案:让B1和B2虚继承A,C再正常多继承B1和B2即可
(3)虚继承就这么简单,就是为了解决菱形继承的二义性问题而生,和虚函数(为了实现多态特性)并没有直接关系

虚继承的实现原理
(1)虚继承的原理是:虚基类表指针vbptr和虚基类表virtual table
(2)参考:https://blog.csdn.net/xiejingfa/article/details/48028491

在这里插入图片描述

总结

理解什么是组合,一个class类里面有很多其他class类类型的成员变量
理解组合和继承的区别
二义性:执行了一个函数,确不一定是自己想指定的那个
解决方案:用c.A::func()明确的指定调用的是class
虚继承有点像条件编译,引入一次就好,不用重复引入,也能达到引入效果

学习记录,侵权联系删除。
来源:朱老师物联网大课堂

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

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

相关文章

CMakeLists.txt编写思路

近期在linux编写CMakeLists.txt文件&#xff0c;整理了一些思路。 一、编写CMakeLists.txt的基本步骤和思路&#xff1a; 初始化CMake&#xff1a; 使用cmake_minimum_required指令指定CMake的最小版本要求&#xff0c;以确保兼容性。使用project指令定义项目名称和可选的语言…

前端-Cookie篇

文章目录 一、由来什么是Cookie&#xff1f;特点Cookie的类型 二、原理三、Cookie生成机制客户端设置案例 四、属性五、缺陷最后分享一段自己工作中封装的一些关于cookie的公众方法✒️总结 前端Cookie是Web开发中非常重要的一部分&#xff0c;它是服务器发送到用户浏览器并保存…

Mysql索引什么时候会失效

在 MySQL 中&#xff0c;索引是提高查询效率的关键工具&#xff0c;但在某些情况下&#xff0c;索引可能会失效。以下是一些常见的索引失效情况&#xff1a; 使用不等号&#xff08;! 或 <>&#xff09;&#xff1a; 使用不等号会导致索引失效&#xff0c;因为不等号无法…

Python模块ConfigParser读取应用程序的配置文件简单示例

一、模块说明&#xff1a; 系统管理员通常通过文本编辑器编辑这些配置文件&#xff0c;以设置应用程序的默认值&#xff0c;然后应用程序将读取并解析这些配置文件&#xff0c;并根据其中的内容执行对应操作。ConfigParser模块具有read()方法&#xff0c;用于读取配置文件。 …

STM32自己从零开始实操08:STM32主控原理图

由于老师使用的各引脚分门别类的单片机原理图我没有找到&#xff0c;我使用是引脚按顺序摆放的&#xff0c;不方便一个模块一个模块截图展示&#xff0c;所以这部分使用老师的原理图。 一、电源 1.1电源的介绍 1.1.1数字电源和地&#xff08;VDD和VSS&#xff09; 数字电源…

中国各省养老机构数据明细(更新至2024年)

中国养老机构是指为老年人提供集中居住、生活照顾、健康管理、文化娱乐等综合性服务的设施。这些机构包括养老院、福利院、老年公寓等多种形态&#xff0c;既有公立也有民办&#xff0c;遍布城市与农村。 一、数据介绍 数据名称&#xff1a;中国养老机构数据明细 数据范围&am…

[leetcode]minimum-cost-to-reach-destination-in-time 规定时间内到达终点的最小费用

. - 力扣&#xff08;LeetCode&#xff09; class Solution { private:// 极大值static constexpr int INFTY INT_MAX / 2;public:int minCost(int maxTime, vector<vector<int>>& edges, vector<int>& passingFees) {int n passingFees.size();ve…

LinkedList----源码分析

源码介绍 public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable{} 添加过程中的操作&#xff1a; 当创建LinkedList类时&#xff0c;会调用其空参构造方法&#xff0c;将其参…

ipv4和ipv6的兼容性问题

ipv4和ipv6的兼容 现今大多知名网站都是同时支持ipv6和ipv4&#xff0c;这种可以分为两种情况讨论&#xff1a; 一个IPv4的网络和一个IPv6的网络通信;一个IPv6的网络和一一个IPv6的网络通信&#xff0c;但是中间需要经过一一个IPv4的网络。 先以第一种为例&#xff1a; 若一…

昇思大模型——MindFormers的使用----从零开始安装配置环境

MindSpore Transformers套件的目标是构建一个大模型训练、微调、评估、推理、部署的全流程开发套件&#xff0c;提供业内主流的Transformer类预训练模型和SOTA下游任务应用&#xff0c;涵盖丰富的并行特性。期望帮助用户轻松的实现大模型训练和创新研发。 MindSpore Transform…

LeetCode 算法:实现 Trie (前缀树) c++

原题链接&#x1f517;&#xff1a;实现 Trie (前缀树) 难度&#xff1a;中等⭐️⭐️ 题目 Trie&#xff08;发音类似 “try”&#xff09;或者说 前缀树 是一种树形数据结构&#xff0c;用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景&#xff0…

关于C# 开发Winfrom事后总结

一&#xff1a;要求能读取文件夹中视频及图片并判断 private void Form1_Load(object sender, EventArgs e){string foldPath "路径";//获取该目录下的文件 string[] files Directory.GetFiles(foldPath "\\", "*.*", System.IO.SearchOption…

Linux编程第三篇:Linux简介,开源软件简介(Linux是否安全?参考TESEC指标)

业精于勤荒于嬉&#xff0c;行成于思毁于随。 今天这篇算是Linux的正式学习&#xff0c;废话不多说&#xff0c;我们开始吧 第三篇 一、UNIX与Linux发展史1.1、UNIX发展历史和发行版本1.2、UNIX主要发行版本1.3、Linux发展历史1.4、Linux内核版本1.5、Linux主要发行版本 二、开…

渐变且描边文字

效果&#xff1a; 用 background-image&#xff1a;linear-gradient实现渐变、 text-shadow实现描边 元素同时添加&#xff1a; background-image: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(143, 180, 253, 1));-webkit-background-clip: text;background-…

大整数加法C++

大整数加法C 方法代码 方法 小的数在前&#xff0c;大数在后加数、被加数进行翻转&#xff0c;从低位开始加起&#xff0c;因为数组是从0位开始&#xff0c;与正常手工加法不同。设置进位符carry_flag先对小的数进行控制&#xff0c;做加法再对大的数剩下的部分&#xff0c;做…

Spring支持人工智能应用框架-SpringAi

简介 人工智能技术和日益成熟&#xff0c;开发企业级人工智能的应用已成为一个热门的趋势。Spring AI 是一个用于 AI 工程的应用框架&#xff0c;目的是为了简化AI应用的对接、部署、维护和扩展。 SpringAi的灵感来自LangChain和LlamaIndex&#xff0c;但是SpringAi并不是直接…

Python实现动态迷宫生成:自动生成迷宫的动画

文章目录 引言准备工作前置条件 代码实现与解析导入必要的库初始化Pygame定义迷宫生成类主循环 完整代码 引言 迷宫生成算法在游戏开发和图形学中有着广泛的应用。它不仅可以用于创建迷宫游戏&#xff0c;还可以用于生成有趣的图案。在这篇博客中&#xff0c;我们将使用Python…

一文了解java中Optional

文章目录 1. Optional简介2. 常用的接口2.1 常用接口简单使用2.1.1 创建的常用方法2.1.2 获取值的常用方法2.1.3 判定的常用方法2.1.4 判定后的操作方法2.2 map方法介绍 2.2 其他方法2.2.1 Filter 方法2.2.2 FlatMap 方法 3. 常用的实例4. 总结 1. Optional简介 Optional是在ja…

基于Java的校园交友网站系统

你好&#xff0c;我是专注于计算机技术研究的学姐码农小野。如果你对校园交友网站系统的构建或者相关技术感兴趣&#xff0c;欢迎私信交流。 开发语言 Java 数据库 MySQL 技术 Java语言、SpringBoot框架、B/S结构 工具 MyEclipse、Navicat、Maven 系统展示 首页 个人…

Postman:Body类型中的x-www-from-urlencoded参数可以接受GET请求吗?

不可以 今天学习Spring Web MVC&#xff0c;在借助Postman学习 RequestMapping 注解时&#xff0c;发现Body类型中的x-www-from-urlencoded参数不支持GET请求。 按理说 RequestMapping 注解可以支持全部类型的请求&#xff0c;但为何在这里不能支持GET请求呢&#xff1f; 以下是…