C++学习笔记----4、用C++进行程序设计(四)---- 复合关系与继承关系之间的细线

news2024/11/16 2:36:27

        在现实世界只是很容易区分对象之间是复合关系还是继承关系。没有人会说桔子有一个水果--而只能是桔子是一种水果。但是,在代码中,有时候就不是那么清晰了。

        设想有一个代表关联数组的假想类,将一个键影射到一个值的数据结构。例如,一家保险公司可以使用一个AssociativeArray类将成员ID影射到一个名字,这样的话,给出一个ID,就会很容易地找到对应的成员的名字。成员ID就是键,成员名字就是值。

        在标准关联数组实现中,一个键与一个值相关联。如果ID 12345影射到成员名字为“张三”,它就不能再影射到成员名字“李四”。在大部分实现中,如果你想对一个已经有值的键再加第二个值,原来的值就会消失。换句话说,如果ID 12345影射到了“张三”,你又给ID 12345赋了一个“李四”,那么张三就会马上脱保。这个可以以下顺序展示,对假设的insert()成员函数调用了再次,关联数组的内容结果如下:

myArray.insert(12345, "张三");
12345“张三”【字符串】
myArray.insert(12345, "李四");
12345“李四”【字符串】

        使用像关联数组但是允许给定的键有多个值的数据结构并不难。像在保险的那个例子中,一个家庭可能有多个名字对应到了同一个ID。因为这样的一个数据结构与关联数组比较类似,去稍微修改一下其功能还是不错的。一个关联数组对于一个键只能有一个值,但这个值可以是任何值。除了字符串之外,也可以是一个集合(比如vector),一个键包含了多个值。对于一个已有的ID来讲,每次增加一个成员,就是给集合增加了一个名字。将以以下顺序起作用:

Collection collection;                 // 声名一个集合.
collection.insert("张三");             // 给集合添加一个新的元素.
myArray.insert(12345, collection);     //将集合插入数组.
12345{“张三”}【集合】
Collection collection { myArray.get(12345) }; // 访问已有集合.
collection.insert("李四");                     // 集合中增加一个新元素.
myArray.insert(12345, collection);             // 用更新后的集合进行替换
12345{“李四”}【集合】

        使用集合而不是字符串会比较讨厌,需要大量重复的代码。最好将这个多值功能封装到一个单独的类里面,可能会叫做MultiAssociativeArray,MultiAssociativeArray类与AssociativeArray比较像,除了背后的实现,它会存储集合的每一个字符串值而不是一个单独的字符串。当然了,MultiAssociativeArray在某种程度上与AssociativeArray相关联,因为它依然使用关联数组来保存数据。不清晰的是这种关系到底是复合关系还是继承关系。

        我们先来说继承关系,先认为MultiAssociativeArray是AssociativeArray的继承类。最终我们会认为这是一个坏主意,但让我们做一个坏的设计的例子。MultiAssociativeArray必须覆盖成员函数,拉回数组的接入,这样的话,或者生成集合并添加成员,或者访问已有集合并添加成员。也必须覆盖访问值的成员函数。这就复杂了,虽然:覆盖后的get()成员函数需要返回一个单独的值,而不是一个集合。那MultiAssociativeArray应该返回什么呢?一个选择就是返回与键相关联的第一个值。可以加一个getAll()的成员函数来返回与键相关联的所有值。这比较像一个可信的设计。虽然它覆盖了基础类的所有成员函数,但它仍然使用了基础类的所有成员函数。下图为其UML类图。

           现在再来考虑一下复合关系,MultiAssociativeArray是自身的类,但是它包含了一个AssociativeArray对象。它可能有一个与AssociativeArray相类似的接口,但是不需要一样。背后的实际情况是,当用户给MultiAssociativeArray添加东西时,实际是在集合中添加了一个AssociativeArray对象。这看起来很完美,如下图:

        好了,哪种解决方案是对的?看起来没有正确答案,但大量的实践告诉我们,在这两种方法中复合关系通常更好。主要原因是不需要担心保持关联数组功能的情况下允许修改暴露在外的接口。例如,上面图示的get()成员函数就被修改成了getAll(),在MultiAssociativeArray中很清晰地对于给定的键获得了其所有值。还有,对于复合关系,你不需要担心关联数组功能的渗漏。例如,对于继承关系,如果关联数组支持一个能够获得值的总数的成员函数,它就会报告集合的数字,除非MultiAssociativeArray知道去覆盖它。但大家对这种渗露一般都不会太注意,会造成很大的问题。

         也就是说,有人会提出一种这样的观点,MultiAssociativeArray实际上就是带有一些新的功能的AssociativeArray,那它应该是一种继承关系。这种观点认为在两种关系之间有时候有一条细线,你需要考虑类要怎样用,是否你要建立的就是从其他类中利用一些功能,还是确实是对类进行了修改或者增加了新功能。

        以下列表列出了对MultiAssociativeArray类使用哪种方法的赞成和反对的意见:

继承关系复合关系
赞成原因

从基础上来说,是对于不同特点的相同的抽象。

提供了(绝大多数)与AssociativeArray相同的成员函数

MultiAssociativeArray可以有任何有用的成员函数而不必担心AssociativeArray有的成员函数。

实现上可以进行任何除了AssociativeArray之外的修改,只要不改变对外暴露的成员函数。

反对原因

关联数组的定义就是一个键对着一个值。说MultiAssociativeArray是一个数组就是对数组的亵渎!

MultiAssociativeArray覆盖了AssociativeArray的两个成员函数,这就是设计出了问题的强烈信号。

AssociativeArray的不知道或者不合适的属性或成员函数可能是对MultiAssociativeArray的渗漏。

某种意义上,MultiAssociativeArray通过新的成员函数重新造了轮子。

AssociativeArray的一些增加的属性与成员函数可能会比较有用。

               在这个案例中不使用继承关系的原因是很站得住脚的。还有,利斯科夫取代原理(LSP)可以帮助你在使用继承与复合关系之间做出决定。该原理指出,在不改变行为的前提下是可以使用继承类而不是基类的。应用到这个例子中,它指出这一定是一个复合关系,因为在使用AssociativeArray之前无法直接使用MultiAssociativeArray。如果你硬要这么干的话,行为就会发生改变。例如,AssociativeArray的insert()成员函数对于在数组中已经存在的同样的键改掉了原来的值,而MultiAssociativeArray不会改掉这些值。

        以上两种解决方案实际上不是仅有的可能的解决方案。其他的选择可以是让AssociativeArray包含一个MultiAssociativeArray,或者是两者都继承于一个通用的基类,等等。对于特定的设计你可以想出多种解决方案。

        如果你必须要在这两种关系之间进行选择,我还是推荐,根据多年的经验,使用复合关系吧。

        记住,在这儿展示继承关系与复合关系之间的不同的AssociativeArray与MultiAssociativeArray,在你自己的代码中,推荐使用标准关联数组类而不是要自己去写。C++标准库提供了std::map可以代替AssociativeArray,std::multimap可以代替MultiAssociativeArray。

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

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

相关文章

python画图高斯平滑均值曲线

注:细线是具体值,粗线是高斯平滑处理后的均值曲线 #codinggbk import matplotlib.pyplot as plt import numpy as np from scipy.ndimage import gaussian_filter1d# 生成一些示例数据 np.random.seed(0) timesteps np.linspace(1000, 0, 1000) data 0.4 0.2 * np.random.r…

并查集(路径压缩、按秩合并、按大小合并)

文章目录 并查集简单介绍:初始化:如何查找?如何合并?优化如下:路径压缩:代码: 按秩合并:**代码:** 启发式合并(按大小合并):代码: 例题…

E5063A-011 时域分析/测试向导程序

矢量网络分析 E5063A 选件 011 E5063A-011 时域分析/测试向导程序 不容错过! 概述 Keysight E5063A ENA 系列 PCB 分析仪是较佳的 PCB 生产测试解决方案,可提供阻抗(TDR)和回波损耗(S 参数)测量能力。…

11091 最优自然数分解问题(优先做)

### 简短思路 #### 问题&#xff08;1&#xff09;&#xff1a;将n分解为若干个互不相同的自然数之和&#xff0c;且使这些自然数的乘积最大 1. 对于n < 4的情况&#xff0c;直接返回特定值。 2. 对于n > 4的情况&#xff0c;使用贪心策略&#xff0c;将n分解为从2开始的…

证书学习(一)keytool 工具使用介绍

目录 一、keytool 简介1.1 什么是 keytool&#xff1f;1.2 主要功能&#xff1a;1.3 使用场景1.4 常用命令1.5 默认参数 二、keytool 用法说明2.1 基本使用2.2 创建密钥库和密钥条目2.3 查看密钥库信息2.4 导出密钥库条目证书2.5 导入信任证书到密钥库2.6 打印证书内容2.7 删除…

零工市场小程序应该有什么功能?

数字经济现如今正飞速发展&#xff0c;零工市场小程序在连接雇主与自由职业者方面发挥着越来越重要的作用。一个高效的零工市场小程序不仅需要具备基础的信息发布与匹配功能&#xff0c;还应该涵盖交易管理、安全保障以及个性化服务等多个方面。 那么&#xff0c;零工市场小程…

为什么企业跨国组网建议用SD-WAN?

SD-WAN成为企业跨国组网的首选方案&#xff0c;主要因为它在灵活性、智能化管理以及数据安全等方面具备显著优势。在企业进行跨国组网时&#xff0c;往往会面临网络连接复杂、流量管理难度大以及数据安全等诸多挑战&#xff0c;而SD-WAN能够有效应对这些难题。 首先&#xff0c…

Docker续1:

一、打包传输 1.打包 [rootlocalhost ~]# systemctl start docker [rootlocalhost ~]# docker save -o centos.tar centos:latest [rootlocalhost ~]# ls anaconda-ks.cfg centos.tar 2.传输 [rootlocalhost ~]# scp centos.tar root192.168.1.100:/root 3.删除镜像 [r…

场外个股期权杠杆率是多少如何计算倍数?

今天带你了解场外个股期权杠杆率是多少如何计算倍数&#xff1f;场外个股期权的杠杆大小不是固定的&#xff0c;而是取决于期权合约的价值和标的资产的价值之间的比例&#xff0c;一般来说场外个股期权的杠杆率大概在5-30倍甚至更高左右。 场外个股期权杠杆率是多少&#xff1…

罗德与施瓦茨RS SMW200A 最实用的一款矢量信号发生器

Rohde & Schwarz SMW200A 是一款适用于最苛刻应用的矢量信号发生器。由于其灵活性、性能和直观的操作&#xff0c;它是生成复杂、高质量数字调制信号的完美工具。 罗德与施瓦茨 SMW200A 是开发新型宽带通信系统、验证 3G 和 4G 基站或航空航天和国防领域所需的数字调制信号…

【软考】cpu的组成

目录 1. 说明2. cpu结构图3. 运算器3.1 说明3.2 主要功能3.3 算术逻辑单元3.4 累加寄存器3.5 数据缓冲寄存器DR3.6 状态条件寄存器PSW 4. 控制器4.1 说明4.2 指令寄存器(IR)4.3 程序计数器(PC)4.4 地址寄存器(AR)4.5 指令译码器(DD) 5. 寄存器组6. 例题6.1 例题1 1. 说明 1.cp…

Lighthouse ApexZ 尘埃粒子计数器审计追踪 数据完整性

在大型制药企业中&#xff0c;高效、准确且安全的样本处理与数据管理至关重要。这些企业不仅需要确保产品质量符合严格的监管要求&#xff0c;还需要优化流程以提高生产效率和降低成本。结合您提到的LIMS&#xff08;实验室信息管理系统&#xff09;和Lighthouse ApexZ便携式空…

行星搅拌炒锅的优点有哪些?

1、容积大&#xff0c;产量高。 2、火力大&#xff0c;独特的燃烧装置&#xff0c;升温快&#xff0c;温度高&#xff0c;炒出的物料色泽鲜艳&#xff0c;口味纯正。 3、不糊锅&#xff0c;独特的搅拌装置&#xff0c;可以覆盖锅体的每一个角落&#xff0c;使物料不糊锅&…

《黑神话 悟空》大火,通关后部分景区可免门票,72处《黑神话 悟空》取景地汇总!

重要提醒&#xff01;打通关的天命人们 免门票了&#xff01;72处《黑神话 悟空》取景地汇总。 8月20日&#xff0c;首个国产3A大作《黑神话:悟空》上线&#xff0c;这几天&#xff0c;大家基本很难不刷到这个热点。在这个游戏中&#xff0c;去了全国多个景区取景&#xff0c;…

城乡燃气安全监管平台 打造城市安全防护网

随着城市化进程的不断加快&#xff0c;燃气已成为现代生活中不可或缺的重要能源。然而&#xff0c;传统燃气管理方式的局限性逐渐显现&#xff0c;难以应对日益增长的安全监管需求。为此&#xff0c;旭华智能基于其在智慧城市领域的深厚积累&#xff0c;推出了燃气安全监管物联…

Spring Cloud + Easy Excel导出表格

在现代应用开发中&#xff0c;数据的导出和处理是一个非常常见的需求。Spring Cloud 和 Easy Excel 是两个强大的工具&#xff0c;可以帮助我们高效地完成这个任务。本文将介绍如何将这两个工具结合起来&#xff0c;实现表格数据的导出功能。 1.环境准备 在开始之前&#xff0…

shellcode汇编复习

shellcode汇编复习 一、 汇编代码复习二、 基础寄存器1. EAX (Accumulator Register)2. EBX (Base Register)3. ECX (Count Register)4. EDX (Data Register)5. ESI (Source Index Register)6. EDI (Destination Index Register) 二、 基础指令1. mov - 数据传送2. add - 加法3…

vue js 前端同时下载多个文件,前端多文件下载

在日常需求中&#xff0c;一般情况下&#xff0c;单次点击下载文件数量一般是一个&#xff0c;当然也有多个文件同时下载的需求&#xff0c;由于浏览器机制&#xff0c;不支持直接多个文件下载&#xff0c;所有需要特殊处理 案例图 不多说了&#xff0c;直接上代码 //下载文…

Transformer经典模型实战:零基础训练一个面向中文的T5模型(Text to Text Transfer Transformer)

scient scient一个用python实现科学计算相关算法的包&#xff0c;包括自然语言、图像、神经网络、优化算法、机器学习、图计算等模块。 scient源码和编译安装包可以在Python package index获取。 The source code and binary installers for the latest released version ar…