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

 

目录

一、简介

继承

组合

二、继承

三、组合

四、案例说明

4.1一个电子商务系统

4.1.1继承方式

在上述代码中,Order类继承自User类。通过继承,Order类获得了User类的成员函数和成员变量,并且可以添加自己的特性。我们重写了displayInfo()函数,以便在Order类中显示订单相关信息。4.1.2组合方式


一、简介

当涉及到代码重用时,继承和组合是两种常见的机制。下面将更详细地介绍它们的特点、使用方式以及各自的优缺点。

  1. 继承

    • 特点:继承是一种创建新类的方式,通过继承已有类的属性和方法来构建新类。在继承关系中,子类(也称为派生类)继承了父类(也称为基类)的成员变量和成员函数,并且可以添加自己的特性。
    • 使用方式:在C++中,可以使用classstruct关键字定义类,在定义派生类时,使用冒号:指定继承关系。在继承中,派生类可以访问父类的公有成员,但不能访问私有成员。
    • 优点:
      • 代码重用:通过继承可以重用基类的代码,减少重复编写相似代码的工作量。
      • 层次结构:继承可以创建一个层次结构,通过将类组织成父子关系,可以更好地组织和管理代码。
    • 缺点:
      • 紧耦合:继承会在派生类和基类之间创建紧密的依赖关系,如果基类发生变化,可能会影响到所有的派生类。
      • 多继承问题:多继承可能引发命名冲突和复杂性增加的问题,需要小心处理。
  2. 组合

    • 特点:组合是一种通过在一个类中包含另一个类的对象来实现代码重用的机制。在组合关系中,一个类(称为组合类)包含另一个类(称为成员类)的对象作为成员变量,通过调用成员对象的方法来实现自己的功能。
    • 使用方式:在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继承了基类Animaleat方法,并添加了自己的bark方法。通过创建Dog对象,我们可以调用继承的eat方法和派生类自己的bark方法。

优点:

  1. 代码重用:继承允许派生类重用基类的代码,避免了重复编写相似的代码。
  2. 层次结构:继承可以创建一个层次结构,通过将类组织成父子关系,可以更好地组织和管理代码。

缺点:

  1. 紧耦合:继承会在派生类和基类之间创建紧密的依赖关系,如果基类发生变化,可能会影响到所有的派生类。
  2. 多继承问题:多继承可能会引发命名冲突和复杂性增加的问题。

三、组合

组合是一种通过在一个类中包含另一个类的对象来实现代码重用的机制。在组合关系中,一个类(组合类)包含另一个类(成员类)的对象作为成员变量。下面是一个示例:

#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对象的方法实现自己的功能。

优点:

  1. 松耦合:组合关系比继承关系更加松散,类之间的依赖关系相对较弱,修改一个类不会影响到其他类。
  2. 灵活性:组合允许动态地改变成员对象,可以在运行时替换成员对象,提供更大的灵活性。

缺点:

  1. 冗余代码:组合可能导致一些重复代码,需要在组合类中转发成员对象的方法。
  2. 对象管理:组合类需要负责创建和管理成员对象,增加了额外的工作量。

结论: 继承和组合都是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类的方法来处理用户相关的操作。

总结: 在这个案例中,我们展示了继承和组合两种不同的代码重用方式。继承适用于存在"是一种"关系的类,并且可以直接使用基类的成员函数和成员变量。组合适用于存在"有一个"关系的类,其中一个类作为另一个类的成员变量,通过调用成员对象的方法来实现功能。选择使用继承还是组合取决于具体的需求和设计目标,需要权衡各自的优缺点来做出决策。

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

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

相关文章

【java八股文】之Redis基础篇

1、Redis有哪几种基本的数据类型 字符串类型&#xff1a;用于存储文章的访问量Hash&#xff1a;用来存储key-value的数据结构&#xff0c;当单个元素比较小和元素数量比较少的时候 &#xff0c;底层是用ziplist存储。通常可以用来存储一些对象之类的List: 底层采用的quicklist …

2024儿童台灯哪个品牌更护眼推荐?五款知名品牌台灯推荐

只要有了娃&#xff0c;家长的吃穿用度可能不会特别讲究&#xff0c;但总想给孩子好的东西&#xff0c;尤其是关系到他们身心健康的&#xff0c;可以说是一掷千金。特别是眼睛视力方面&#xff0c;特别担心会遗传给孩子&#xff0c;自从他上幼儿园&#xff0c;我就一直在物色一…

WSL不同版本的Ubuntu更换清华镜像,加速Ubuntu软件下载速度

文章目录 不同版本的Ubuntu使用清华镜像&#xff0c;加速Ubuntu软件下载速度1. 备份源软件配置文件2. 复制镜像源3. 修改软件源配置文件4. 更新软件包列表&#xff0c;升级软件包等内容5. 从仓库中下载其它软件可能存在的问题 不同版本的Ubuntu使用清华镜像&#xff0c;加速Ubu…

鸿蒙Harmony--LocalStorage--页面级UI状态存储详解

走的太急疼的是脚&#xff0c;逼的太紧累的是心&#xff0c;很多时候&#xff0c;慢一点也没关系&#xff0c;多给自己一些耐心和等待&#xff0c;保持热爱&#xff0c;当下即是未来&#xff0c;生活自有安排! 目录 一&#xff0c;定义 二&#xff0c;LocalStorageProp定义 三…

Java Web 开发 从入门到实战(课后习题)

第1章 Web 前端基础 1.在以下标记中&#xff0c;用于改置页面标题的是&#xff08;&#xff09;。 A. <title> B. <caption> C. <head> D. <html> 注&#xff1a;caption是表格名称&#xff08;标题&#xff09; 2. 若设计网页的背景图形为bg.png&…

使用Mixtral-offloading在消费级硬件上运行Mixtral-8x7B

Mixtral-8x7B是最好的开放大型语言模型(LLM)之一&#xff0c;但它是一个具有46.7B参数的庞大模型。即使量化为4位&#xff0c;该模型也无法在消费级GPU上完全加载(例如&#xff0c;24 GB VRAM是不够的)。 Mixtral-8x7B是混合专家(MoE)。它由8个专家子网组成&#xff0c;每个子…

Linux--LNMP架构及应用部署

4.2 LNMP架构及应用部署 4.2.1构建LNMP网站平台 为了与Nginx、PHP环境保持一致&#xff0c;仍选择采用源代码编译的方式安装MySQL组件。以5.5.22 版本为例&#xff0c;安装过程如下所述。 &#xff08;1&#xff09;编译安装MySQL。 [rootnode01 ~]# yum -y install ncurses-…

Java中锁的解决方案

前言 在上一篇文章中&#xff0c;介绍了什么是锁&#xff0c;以及锁的使用场景&#xff0c;本文继续给大家继续做深入的介绍&#xff0c;介绍JAVA为我们提供的不同种类的锁。 JAVA为我们提供了种类丰富的锁&#xff0c;每种锁都有不同的特性&#xff0c;锁的使用场景也各不相…

Java 面试题 - 多线程并发篇

线程基础 创建线程有几种方式 继承Thread类 可以创建一个继承自Thread类的子类&#xff0c;并重写其run()方法来定义线程的行为。然后可以通过创建该子类的实例来启动线程。 示例代码&#xff1a; class MyThread extends Thread {public void run() {// 定义线程的行为} …

JUC02同步和锁

同步&锁 相关笔记&#xff1a;www.zgtsky.top 临界区 临界资源&#xff1a;一次仅允许一个进程使用的资源成为临界资源 临界区&#xff1a;访问临界资源的代码块 竞态条件&#xff1a;多个线程在临界区内执行&#xff0c;由于代码的执行序列不同而导致结果无法预测&am…

近视的孩子用什么灯?学生考研护眼台灯推荐

随着时代快速发展&#xff0c;2022年我国近视人数达到了7亿&#xff0c;呈现低龄化趋势&#xff0c;儿童及青少年人数占了53.8%。现在学业负担都很重&#xff0c;每个家长都不希望自己的孩子近视或加深近视了&#xff0c;都会想尽一切办法保护视力。而护眼台灯就成了家长购买台…

Qt中QGraphicsView架构下实时鼠标绘制图形

上一章节介绍了关于QGraphicsView的基础讲解&#xff0c;以及简单的类图创建&#xff0c;由上一章节中最后展示的动画效果来看&#xff0c;今年主要讲述如何在QGraphicsView架构下&#xff0c;实时拖动鼠标绘制图形&#xff01; 今天主要以矩形为例&#xff0c;再来看一下展示…

苹果电脑RAW图像处理软件Capture One Pro 22 mac软件介绍

Capture One Pro 22 for mac是一款专业的RAW文件转换器和图像编辑软件&#xff0c;拥有更新的处理引擎、市场领先的性能和强大的新功能&#xff0c;可为 500 多台高端相机提供具有美丽色彩和令人难以置信的细节的终极图像质量。 Capture One Pro 22 for Mac版软件介绍 Capture…

Vue-17、Vue人员列表过滤(案例)

1、watch实现 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>列表渲染过滤</title><script type"text/javascript" src"https://cdn.jsdelivr.net/npm/vue2/dist/vue.js&qu…

JavaScript Web Worker用法指南

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》 ​ ​ ✨ 前言 Web Worker可以将耗时任务放到后台执行,避免阻塞UI。本文将详细介绍Web Worker的用法,让你…

FineBI实战项目一(22):各省份订单个数及订单总额分析开发

点击新建组件&#xff0c;创建各省份订单个数及订单总额组件。 选择自定义图表&#xff0c;将province拖拽到横轴&#xff0c;将cnt和total拖拽到纵轴。 调节纵轴的为指标并列。 修改横轴和纵轴的标题。 修改柱状图样式&#xff1a; 将组件拖拽到仪表板。 结果如下&#xff1a;…

【专业英语】计算机专业英语(第三版)清华大学出版社

专业英语 部分专业名词 短语 在这里插入图片描述

FlinkCDC的分析和应用代码

前言&#xff1a;原本想讲如何基于Flink实现定制化计算引擎的开发&#xff0c;并以FlinkCDC为例介绍&#xff1b;发现这两个在表达上不知以谁为主&#xff0c;所以先分析FlinkCDC的应用场景和技术实现原理&#xff0c;下一篇再去分析Flink能在哪些方面&#xff0c;做定制化计算…

U盘用完到底能不能直接拔?一篇搞懂

有没有人懂这种情况&#xff01;&#xff01; 传输完文件之后&#xff0c;觉得大功告成 以十分帅气的姿势 and 迅雷不及掩耳之势 “咻”地一下把U盘直接给……拔掉了…… 然后瞬间想起没有安全退出&#xff0c;陷入深深的懊悔…… &#xff08;甚至还要再花时间&#xff0…

WebServer 跑通/运行/测试(详解版)

&#x1f442; 椿 - 沈以诚 - 单曲 - 网易云音乐 目录 &#x1f382;前言 &#x1f33c;跑通 &#xff08;1&#xff09;系统环境 &#xff08;2&#xff09;克隆源码 &#xff08;3&#xff09;安装和配置 Mysql &#xff08;4&#xff09;写 sql 语句 &#xff08;5&…