C++代码重用:继承与组合的比较

目录
一、简介
继承
组合
二、继承
三、组合
四、案例说明
4.1一个电子商务系统
4.1.1继承方式
在上述代码中,Order类继承自User类。通过继承,Order类获得了User类的成员函数和成员变量,并且可以添加自己的特性。我们重写了displayInfo()函数,以便在Order类中显示订单相关信息。4.1.2组合方式
一、简介
当涉及到代码重用时,继承和组合是两种常见的机制。下面将更详细地介绍它们的特点、使用方式以及各自的优缺点。
-
继承
- 特点:继承是一种创建新类的方式,通过继承已有类的属性和方法来构建新类。在继承关系中,子类(也称为派生类)继承了父类(也称为基类)的成员变量和成员函数,并且可以添加自己的特性。
- 使用方式:在C++中,可以使用
class或struct关键字定义类,在定义派生类时,使用冒号:指定继承关系。在继承中,派生类可以访问父类的公有成员,但不能访问私有成员。 - 优点:
- 代码重用:通过继承可以重用基类的代码,减少重复编写相似代码的工作量。
- 层次结构:继承可以创建一个层次结构,通过将类组织成父子关系,可以更好地组织和管理代码。
- 缺点:
- 紧耦合:继承会在派生类和基类之间创建紧密的依赖关系,如果基类发生变化,可能会影响到所有的派生类。
- 多继承问题:多继承可能引发命名冲突和复杂性增加的问题,需要小心处理。
-
组合
- 特点:组合是一种通过在一个类中包含另一个类的对象来实现代码重用的机制。在组合关系中,一个类(称为组合类)包含另一个类(称为成员类)的对象作为成员变量,通过调用成员对象的方法来实现自己的功能。
- 使用方式:在C++中,可以在组合类中声明成员对象作为成员变量,并在组合类的方法中调用成员对象的方法来实现功能。
- 优点:
- 松耦合:组合关系比继承关系更加松散,类之间的依赖关系相对较弱,修改一个类不会影响到其他类。
- 灵活性:组合允许动态地改变成员对象,可以在运行时替换成员对象,提供更大的灵活性。
- 缺点:
- 冗余代码:组合可能导致一些重复代码,需要在组合类中转发成员对象的方法。
- 对象管理:组合类需要负责创建和管理成员对象,增加了额外的工作量。
在选择使用继承还是组合时,需要考虑以下因素:
- 类的关系:如果存在一种“is-a”的关系,即派生类是基类的一种特殊形式,可以选择使用继承。例如,
Dog可以被视为Animal的一种特殊类型。- 代码重用程度:如果需要重用大量基类代码,可以选择继承。继承允许派生类直接使用基类的功能,减少了代码编写的工作量。
- 灵活性要求:如果需要更灵活的类关系和低耦合度,可以选择组合。组合允许动态替换成员对象,提供更大的灵活性。
二、继承
继承是一种通过创建一个新类来继承已有类的属性和方法的机制。在继承关系中,子类(派生类)可以继承父类(基类)的成员变量和成员函数,并且可以添加自己的特性。下面是一个简单的示例:
#include <iostream>class Animal {
public:void eat() {std::cout << "Animal is eating." << std::endl;}
};class Dog : public Animal {
public:void bark() {std::cout << "Dog is barking." << std::endl;}
};int main() {Dog dog;dog.eat(); // 输出 "Animal is eating."dog.bark(); // 输出 "Dog is barking."return 0;
}
在这个示例中,我们定义了一个基类Animal和一个派生类Dog。派生类Dog继承了基类Animal的eat方法,并添加了自己的bark方法。通过创建Dog对象,我们可以调用继承的eat方法和派生类自己的bark方法。
优点:
- 代码重用:继承允许派生类重用基类的代码,避免了重复编写相似的代码。
- 层次结构:继承可以创建一个层次结构,通过将类组织成父子关系,可以更好地组织和管理代码。
缺点:
- 紧耦合:继承会在派生类和基类之间创建紧密的依赖关系,如果基类发生变化,可能会影响到所有的派生类。
- 多继承问题:多继承可能会引发命名冲突和复杂性增加的问题。
三、组合
组合是一种通过在一个类中包含另一个类的对象来实现代码重用的机制。在组合关系中,一个类(组合类)包含另一个类(成员类)的对象作为成员变量。下面是一个示例:
#include <iostream>class Engine {
public:void start() {std::cout << "Engine is starting." << std::endl;}
};class Car {
private:Engine engine;public:void start() {engine.start();std::cout << "Car is starting." << std::endl;}
};int main() {Car car;car.start(); // 输出 "Engine is starting." 和 "Car is starting."return 0;
}
在这个示例中,我们定义了一个成员类Engine和一个组合类Car。组合类Car包含一个Engine对象作为成员变量,并通过调用Engine对象的方法实现自己的功能。
优点:
- 松耦合:组合关系比继承关系更加松散,类之间的依赖关系相对较弱,修改一个类不会影响到其他类。
- 灵活性:组合允许动态地改变成员对象,可以在运行时替换成员对象,提供更大的灵活性。
缺点:
- 冗余代码:组合可能导致一些重复代码,需要在组合类中转发成员对象的方法。
- 对象管理:组合类需要负责创建和管理成员对象,增加了额外的工作量。
结论: 继承和组合都是C++中常用的代码重用机制,它们各有优缺点。在选择使用哪种机制时,需要根据具体的需求和设计要求进行权衡。如果需要创建一个层次结构或者重用大量基类代码,可以选择继承;如果需要更灵活的类关系和低耦合度,可以选择组合。重要的是根据实际情况选择适合的代码重用方式,并结合良好的设计原则来编写高质量的代码。
四、案例说明
4.1一个电子商务系统
其中有两个重要的类:User(用户)和Order(订单)。用户可以下订单,并且一个用户可以有多个订单,因此User类和Order类之间存在一种关系。我们将使用继承和组合两种方式来设计这两个类之间的关系。
4.1.1继承方式
#include <iostream>
#include <string>// 用户类
class User {
private:std::string name;
public:User(const std::string& name) : name(name) {}void setName(const std::string& newName) {name = newName;}std::string getName() const {return name;}virtual void displayInfo() const {std::cout << "User: " << name << std::endl;}
};// 订单类,继承自用户类
class Order : public User {
private:std::string orderId;
public:Order(const std::string& name, const std::string& orderId): User(name), orderId(orderId) {}void setOrderId(const std::string& newOrderId) {orderId = newOrderId;}std::string getOrderId() const {return orderId;}void displayInfo() const override {std::cout << "User: " << getName() << ", OrderId: " << orderId << std::endl;}
};int main() {User user("John");Order order("John", "12345");user.displayInfo();order.displayInfo();return 0;
}
在上述代码中,Order类继承自User类。通过继承,Order类获得了User类的成员函数和成员变量,并且可以添加自己的特性。我们重写了displayInfo()函数,以便在Order类中显示订单相关信息。4.1.2组合方式
#include <iostream>
#include <string>// 用户类
class User {
private:std::string name;
public:User(const std::string& name) : name(name) {}void setName(const std::string& newName) {name = newName;}std::string getName() const {return name;}void displayInfo() const {std::cout << "User: " << name << std::endl;}
};// 订单类,组合了用户类对象
class Order {
private:std::string orderId;User user;
public:Order(const std::string& name, const std::string& orderId): user(name), orderId(orderId) {}void setOrderId(const std::string& newOrderId) {orderId = newOrderId;}std::string getOrderId() const {return orderId;}void displayInfo() const {std::cout << "User: " << user.getName() << ", OrderId: " << orderId << std::endl;}
};int main() {User user("John");Order order("John", "12345");user.displayInfo();order.displayInfo();return 0;
}
在这个例子中,Order类包含了一个User类的对象作为成员变量。通过组合,Order类可以调用User类的方法来处理用户相关的操作。
总结: 在这个案例中,我们展示了继承和组合两种不同的代码重用方式。继承适用于存在"是一种"关系的类,并且可以直接使用基类的成员函数和成员变量。组合适用于存在"有一个"关系的类,其中一个类作为另一个类的成员变量,通过调用成员对象的方法来实现功能。选择使用继承还是组合取决于具体的需求和设计目标,需要权衡各自的优缺点来做出决策。
相关文章:
C++代码重用:继承与组合的比较
目录 一、简介 继承 组合 二、继承 三、组合 四、案例说明 4.1一个电子商务系统 4.1.1继承方式 在上述代码中,Order类继承自User类。通过继承,Order类获得了User类的成员函数和成员变量,并且可以添加自己的特性。我们重写了displayI…...
暴打小苹果
欢迎来到程序小院 暴打小苹果 玩法:鼠标左键点击任意区域可发招暴打,在苹果到达圆圈时点击更容易击中, 30秒挑战暴打小苹果,打中一次20分,快去暴打小苹果吧^^。开始游戏https://www.ormcc.com/play/gameStart/247 htm…...
【BetterBench】2024年都有哪些数学建模竞赛和大数据竞赛?
2024年每个月有哪些竞赛? 2024年32个数学建模和数据挖掘竞赛重磅来袭!!! 2024年数学建模和数学挖掘竞赛时间目录汇总 一月 (1)2024年第二届“华数杯”国际大学生数学建模竞赛 报名时间:即日起…...
Vue-9、Vue事件修饰符
1、prevent 阻止默认事件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>事件修饰符</title><!--引入vue--><script type"text/javascript" src"https://cdn.jsdeliv…...
前端面试题集合六(高频)
1、vue实现双向数据绑定原理是什么? <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>…...
使用Pygame库创建了一个窗口,并在窗口中加载了一个名为“ball.png“的图片,通过不断改变物体的位置,实现了一个简单的动画效果
import pygame import sys# 初始化Pygame pygame.init()# 创建窗口 screen pygame.display.set_mode((640, 480))# 加载图片 image pygame.image.load("ball.png")# 将物体初始位置设为屏幕左上角 x 0 y 0# 游戏循环 while True:# 处理事件for event in pygame.e…...
常见的AdX程序化广告交易模式有哪些?媒体如何选择恰当的交易模式?
程序化广告的核心目的是:让需求方能自由地选择流量与出价,程序化广告在数字广告投放中的主导地位日益巩固。 程序化广告“交易模式”有哪些?以下是详细解读,帮助媒体选择恰当的交易方式,从而实现广告价值的最大化。 …...
VCG 网格平滑之Laplacian平滑
文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 由于物理采样过程固有的局限性,三维扫描仪获得的网格通常是有噪声的。为了消除这种噪声,所谓的平滑算法被开发出来。这类方法有很多,VCG主要为我们提供了一种是较为经典的Laplace平滑算法,这个方法很多库都有实…...
Jupyter Markdown格式
穿插在程序中,太复杂了喧宾夺主,太简单了不如注释。这样就刚刚好: Headers # header 1 ## header 2 ### header 3 #### header 4Output: header 1 header 2 header 3 header 4 2. Horizontal Line Use any of three to draw a horizon…...
Vue3 实时显示时间
记录一下代码,方便以后使用 参考的文章链接 做了以下修改 修改了formateDate方法中传入参数这个不合理的地方给定时器增加了间隔时间增加了取消定时器的方法 <!-- template中的代码 --> <span>当前时间:{{ nowTime }}</span>// sc…...
详解Java多线程之循环栅栏技术CyclicBarrier
第1章:引言 大家好,我是小黑,工作中,咱们经常会遇到需要多个线程协同工作的情况。CyclicBarrier,直译过来就是“循环屏障”。它是Java中用于管理一组线程,并让它们在某个点上同步的工具。简单来说…...
ebpf学习
学习ebpf相关知识 参考资料: awesome-ebpf 文章目录 初识准备ebpf.io介绍cilium的介绍内核文档Brendan Greggs Blog 的介绍书籍Learning eBPFWhat is eBPF? 交互式环境视频 基础知识学习学习环境搭建书籍阅读 项目落地流程整理环境搭建内核编译bcc环境变量zliblibelflibbpflib…...
【Linux】Linux系统编程——ls命令
【Linux】Linux 系统编程——ls 命令 1.命令概述 ls 命令是 Linux 和其他类 Unix 操作系统中最常用的命令之一。ls 命令是英文单词 list 的缩写,正如 list 的意思,ls 命令用于列出文件系统中的文件和目录。使用此命令,用户可以查看目录中的…...
QA面试题
1、质量保证(QA)是什么? QA代表质量保证。QA 是一组活动,旨在确保开发的软件满足 SRS 文档中提到的所有规范或要求。QA 遵循 PDCA 循环: 计划/Plan - 计划是质量保证的一个阶段,组织在此阶段确定构建高质量软件产品所需的过程。做…...
【国产mcu填坑篇】华大单片机(小华半导体)一、SPI的DMA应用(发送主机)HC32L136
最近需要用华大的hc32l136的硬件SPIDMA传输,瞎写很久没调好,看参考手册,瞎碰一天搞通了。。。 先说下我之前犯的错误,也是最宝贵的经验,供参考 没多看参考手册直接写(即使有点烂仍然提供了最高的参考价值。…...
【前后端的那些事】treeSelect树形结构数据展示
文章目录 tree-selector1. 新增表单组件2. 在父组件中引用3. 父组件添加新增按钮4. 树形组件4.1 前端代码4.2 后端代码 前言:最近写项目,发现了一些很有意思的功能,想写文章,录视频把这些内容记录下。但这些功能太零碎,…...
华为OD机试 - 最长子字符串的长度(二)(Java JS Python C)
题目描述 给你一个字符串 s,字符串 s 首尾相连成一个环形,请你在环中找出 l、o、x 字符都恰好出现了偶数次最长子字符串的长度。 输入描述 输入是一串小写的字母组成的字符串 输出描述 输出是一个整数 备注 1 ≤ s.length ≤ 5 * 10^5s 只包含小写英文字母用例 输入alolob…...
【VRTK】【Unity】【游戏开发】更多技巧
课程配套学习项目源码资源下载 https://download.csdn.net/download/weixin_41697242/88485426?spm=1001.2014.3001.5503 【概述】 本篇将较为零散但常用的VRTK开发技巧集合在一起,主要内容: 创建物理手震动反馈高亮互动对象【创建物理手】 非物理手状态下,你的手会直接…...
Spark 读excel报错,scala.MatchError
Spark3详细报错: scala.MatchError: Map(treatemptyvaluesasnulls -> true, location -> viewfs://path.xlsx, inferschema -> false, addcolorcolumns -> true, header -> true) (of class org.apache.spark.sql.catalyst.util.CaseInsensitiveMap)scala代码…...
【漏洞复现】Office365-Indexs-任意文件读取
漏洞描述 Office 365 Indexs接口存在一个任意文件读取漏洞,攻击者可以通过构造精心设计的请求,成功利用漏洞读取服务器上的任意文件,包括敏感系统文件和应用程序配置文件等。通过利用此漏洞,攻击者可能获得系统内的敏感信息,导致潜在的信息泄露风险 免责声明 技术文章…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
