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接口存在一个任意文件读取漏洞,攻击者可以通过构造精心设计的请求,成功利用漏洞读取服务器上的任意文件,包括敏感系统文件和应用程序配置文件等。通过利用此漏洞,攻击者可能获得系统内的敏感信息,导致潜在的信息泄露风险 免责声明 技术文章…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...
Vue 3 + WebSocket 实战:公司通知实时推送功能详解
📢 Vue 3 WebSocket 实战:公司通知实时推送功能详解 📌 收藏 点赞 关注,项目中要用到推送功能时就不怕找不到了! 实时通知是企业系统中常见的功能,比如:管理员发布通知后,所有用户…...
