依赖倒置 DIP、依赖注入 DI、控制反转 IoC 和工厂模式

1. 依赖倒置

依赖倒置原则(Dependency Inversion Principle, DIP)是 SOLID 原则中的一项,其核心思想是通过抽象解耦高层模块和低层模块,使二者都依赖于抽象而非具体实现

依赖反转/倒置的体现:传统依赖方向是高层模块直接调用低层模块,在源码级别上高层模块依赖低层细节模块。而 DIP 通过抽象反转这种依赖关系,使低层模块的实现在源码级别上依赖高层定义的抽象(视为高层模块的一部分)。

1.1 依赖倒置原则的核心

  1. 高层模块不直接依赖低层模块,二者都应依赖抽象(接口或抽象类,接口由高层模块定义,视为高层模块的一部分)。

  2. 抽象不依赖细节,细节(具体实现)应依赖抽象。

1.2 依赖倒置指导方针

  • 变量不可以持有具体类的引用——改用工厂,避免直接使用 new 持有具体类的引用(new 具体类的操作都封装到工厂中)

  • 不要让类派生自具体类——派生自抽象类或接口,这样就不依赖具体类了

  • 不要覆盖基类中已经实现的方法——如果这样,说明不是一个真正适合被继承的抽象

1.3 示例

场景

  • 高层模块 ReportGenerator 需要生成报告,依赖数据获取功能。

  • 低层模块 MySQLDatabase 和 SQLiteDatabase 提供具体的数据操作。

传统实现(未遵循 DIP)

// 低层模块:直接依赖具体实现
class MySQLDatabase {
public:void connect() { /* MySQL 连接逻辑 */ }std::string fetchData() { return "MySQL 数据"; }
};// 高层模块直接依赖低层具体类
class ReportGenerator {
private:MySQLDatabase db;  // 直接依赖具体实现
public:void generateReport() {db.connect();auto data = db.fetchData();std::cout << "报告数据: " << data << std::endl;}
};

问题ReportGenerator 直接依赖 MySQLDatabase,更换数据库(如改用 SQLite)需修改高层代码。

遵循 DIP 的实现

1、定义抽象接口

class Database {
public:virtual ~Database() = default;virtual void connect() = 0;virtual std::string fetchData() = 0;
};

2、低层模块实现接口

class MySQLDatabase : public Database {
public:void connect() override { /* MySQL 连接逻辑 */ }std::string fetchData() override { return "MySQL 数据"; }
};class SQLiteDatabase : public Database {
public:void connect() override { /* SQLite 连接逻辑 */ }std::string fetchData() override { return "SQLite 数据"; }
};

3、高层模块依赖抽象

class ReportGenerator {
private:Database& db;  // 依赖抽象接口
public:ReportGenerator(Database& database) : db(database) {}  // 依赖注入void generateReport() {db.connect();auto data = db.fetchData();std::cout << "报告数据: " << data << std::endl;}
};

class ReportGenerator {
private:Database& db;  // 依赖抽象接口
public:ReportGenerator(Database& database) : db(database) {}  // 依赖注入void generateReport() {db.connect();auto data = db.fetchData();std::cout << "报告数据: " << data << std::endl;}
};

4、使用示例

int main() {MySQLDatabase mysqlDb;SQLiteDatabase sqliteDb;ReportGenerator report1(mysqlDb);   // 使用 MySQLreport1.generateReport();ReportGenerator report2(sqliteDb);  // 使用 SQLitereport2.generateReport();return 0;
}

1.4 依赖倒置优势

  • 解耦:高层模块不依赖低层具体实现,可灵活替换数据库(如新增 MongoDB 只需实现 Database 接口)。

  • 可维护性:修改低层代码(如优化 MySQLDatabase)不影响高层模块。

  • 可测试性:可通过 Mock 对象(实现 Database 接口)轻松测试 ReportGenerator

1.5 依赖倒置小结

依赖倒置原则通过抽象解耦模块,使依赖关系从“高层 → 低层”变为“高层 → 抽象 ← 低层”,从而提升系统的灵活性和可维护性。在 C++ 中,可通过抽象类(接口)和依赖注入(如构造函数传入接口指针/引用)实现这一原则。

2. 依赖注入 DI

依赖注入(Dependency Injection, DI)是一种将对象依赖关系的外部化技术,其核心思想是:对象不直接创建或管理自己的依赖,而是由外部(调用者或框架)提供依赖的实例。通过这种方式,代码的耦合度降低,灵活性和可测试性显著提高。

2.1 依赖注入的本质

1、控制反转(IoC)

依赖注入是控制反转的一种实现方式。传统代码中,对象自己控制依赖的创建(如 new 一个具体类),而依赖注入将这一控制权交给外部,实现“依赖被注入到对象中”。

2、依赖抽象而非实现

依赖注入通常结合接口或抽象类使用,确保对象依赖的是抽象,而非具体实现(符合依赖倒置原则)。

2.2 依赖注入的三种方式

1. 构造函数注入(最常用)

通过构造函数传递依赖,确保对象在创建时即具备完整依赖。

class NotificationService {
private:MessageSender& sender;  // 依赖抽象接口
public:NotificationService(MessageSender& sender) : sender(sender) {}  // 构造函数注入void sendMessage(const std::string& msg) {sender.send(msg);}
};

2. 属性注入(Setter 注入)

通过公开的成员属性或 Setter 方法动态设置依赖。

class NotificationService {
public:void setSender(MessageSender& sender) {  // Setter 注入this->sender = &sender;}
private:MessageSender* sender;
};

3. 方法注入

通过方法参数传递依赖,适用于临时或局部依赖。

class NotificationService {
public:void sendMessage(MessageSender& sender, const std::string& msg) {  // 方法注入sender.send(msg);}
};

2.3 为什么需要依赖注入?

1. 解耦与可维护性

  • 传统代码:对象内部直接创建依赖,导致紧耦合。

class UserService {
private:
MySQLDatabase db; // 直接依赖具体类
};


若需改用 `SQLiteDatabase`,必须修改 `UserService` 的代码。- **依赖注入**:通过接口解耦,仅需注入不同实现。```cpp
class UserService {
private:Database& db;  // 依赖抽象
public:UserService(Database& db) : db(db) {}
};

2. 可测试性

  • 依赖注入允许在测试时替换为 Mock 对象。

class MockDatabase : public Database { /* 模拟实现 */ };TEST(UserServiceTest) {MockDatabase mockDb;UserService service(mockDb);  // 注入 Mock 对象// 执行测试...
}

3. 扩展性
  • 新增功能时,只需实现新依赖并注入,无需修改现有代码。

class MongoDB : public Database { /* 新数据库实现 */ };MongoDB mongoDb;
UserService service(mongoDb);  // 直接注入新依赖

2.4 C++ 依赖注入的实践技巧

1. 使用智能指针管理生命周期

避免裸指针导致的内存泄漏,使用 std::shared_ptr 或 std::unique_ptr

class NotificationService {
private:std::shared_ptr<MessageSender> sender;  // 智能指针管理依赖
public:NotificationService(std::shared_ptr<MessageSender> sender) : sender(sender) {}
};

2. 结合工厂模式

通过工厂类集中管理依赖的创建逻辑。

class SenderFactory {
public:static std::shared_ptr<MessageSender> createSender(const std::string& type) {if (type == "email") return std::make_shared<EmailSender>();else return std::make_shared<SmsSender>();}
};// 使用工厂创建依赖
auto sender = SenderFactory::createSender("email");
NotificationService service(sender);

3. 依赖注入容器(IoC Container)

在复杂项目中,使用容器自动管理依赖关系(如 Boost.DI)。

#include <boost/di.hpp>
namespace di = boost::di;// 定义接口和实现
class Database { /* ... */ };
class MySQLDatabase : public Database { /* ... */ };// 配置容器
auto injector = di::make_injector(di::bind<Database>().to<MySQLDatabase>()
);// 自动注入依赖
class UserService {
public:UserService(Database& db) { /* ... */ }
};
UserService service = injector.create<UserService>();

2.5 依赖注入的常见误区

1、依赖注入 ≠ 工厂模式

工厂模式负责创建对象,而依赖注入负责传递对象。二者常结合使用,但目的不同。

2、依赖注入 ≠ 必须用框架

即使不用框架(如 Boost.DI),通过构造函数或参数传递依赖,也能实现依赖注入。

3、过度注入问题

若一个类需要注入过多依赖(如超过 4 个),可能设计存在问题,需考虑拆分职责。

2.6 依赖注入小结

  • 依赖注入的核心:将依赖的创建和绑定从对象内部转移到外部。

  • 核心价值:解耦、可测试、可扩展。

C++ 实现关键:

通过接口抽象依赖。

使用构造函数/智能指针传递依赖。

结合工厂模式或 IoC 容器管理复杂依赖关系。

3. 控制反转 IoC

IoC(Inversion of Control,控制反转) 是一种软件设计原则,其核心思想是将程序流程的控制权从开发者转移给框架或容器,以降低代码的耦合度,提高模块化和可维护性。它是实现依赖倒置原则(DIP)的关键机制,也是现代框架(如 Spring、.NET Core)和依赖注入(DI)容器的基础。

3.1 控制反转 IoC vs. 依赖注入 DI

  • IoC(控制反转):广义的设计原则,表示控制权转移的范式。其本质是将程序流程的控制权从开发者转移到框架或容器

  • DI(依赖注入):IoC 的一种具体实现技术,通过外部传递依赖。

关系

  • 依赖注入是控制反转的实现方式之一。

  • 控制反转还可以通过模板方法、回调(关联:好莱坞原则)等方式实现。

  • 使用 IoC 容器(如 Boost.DI)自动管理复杂依赖关系。

4. 工厂模式

尽管依赖倒置和依赖注入都强调面向抽象编程,但在实际编码中仍需创建(new)具体底层组件(ConcreteClass)

工厂模式主要分为三种,严格来说包括 简单工厂模式工厂方法模式 和 抽象工厂模式。以下是它们的核心区别、适用场景及 C++ 示例:

4.1 简单工厂模式(Simple Factory)

有时候简单工厂不被视为正式的设计模式,而是一个编程习惯。

核心思想

  • 通过一个工厂类,根据传入的参数决定创建哪种具体产品对象。

  • 不符合开闭原则(新增产品需修改工厂类逻辑)。

适用场景

  • 产品类型较少且创建逻辑简单。

  • 不需要频繁扩展新类型。

C++ 示例

// 抽象产品
class Shape {
public:virtual void draw() = 0;virtual ~Shape() = default;
};// 具体产品
class Circle : public Shape {
public:void draw() override { std::cout << "画一个圆形" << std::endl; }
};class Square : public Shape {
public:void draw() override { std::cout << "画一个正方形" << std::endl; }
};// 简单工厂类
class ShapeFactory {
public:static Shape* createShape(const std::string& type) {if (type == "circle") return new Circle();else if (type == "square") return new Square();else return nullptr;}
};// 使用示例
int main() {Shape* circle = ShapeFactory::createShape("circle");circle->draw();  // 输出: 画一个圆形delete circle;return 0;
}

4.2 工厂方法模式(Factory Method)

核心思想
  • 定义一个创建对象的抽象方法,由子类决定实例化哪个类。

  • 符合开闭原则(新增产品只需新增子类工厂)。

适用场景
  • 产品类型可能频繁扩展。

  • 需要将对象创建延迟到子类。

C++ 示例

// 抽象产品
class Database {
public:virtual void connect() = 0;virtual ~Database() = default;
};// 具体产品
class MySQL : public Database {
public:void connect() override { std::cout << "连接到 MySQL" << std::endl; }
};class PostgreSQL : public Database {
public:void connect() override { std::cout << "连接到 PostgreSQL" << std::endl; }
};// 抽象工厂
class DatabaseFactory {
public:virtual Database* createDatabase() = 0;virtual ~DatabaseFactory() = default;
};// 具体工厂
class MySQLFactory : public DatabaseFactory {
public:Database* createDatabase() override { return new MySQL(); }
};class PostgreSQLFactory : public DatabaseFactory {
public:Database* createDatabase() override { return new PostgreSQL(); }
};// 使用示例
int main() {DatabaseFactory* factory = new PostgreSQLFactory();Database* db = factory->createDatabase();db->connect();  // 输出: 连接到 PostgreSQLdelete db;delete factory;return 0;
}

4.3 抽象工厂模式(Abstract Factory)

核心思想
  • 提供一个接口,用于创建相关或依赖对象族,而无需指定具体类。

  • 抽象工厂包含多个工厂方法,每个方法负责创建一个产品族中的对象。

适用场景
  • 需要创建一组相关或依赖的对象(例如 GUI 组件:按钮、文本框、下拉菜单等)。

  • 系统需要独立于产品的创建、组合和表示。

C++ 示例

// 抽象产品:按钮
class Button {
public:virtual void render() = 0;virtual ~Button() = default;
};// 具体产品:Windows 按钮
class WindowsButton : public Button {
public:void render() override { std::cout << "Windows 风格按钮" << std::endl; }
};// 具体产品:MacOS 按钮
class MacOSButton : public Button {
public:void render() override { std::cout << "MacOS 风格按钮" << std::endl; }
};// 抽象产品:文本框
class TextBox {
public:virtual void display() = 0;virtual ~TextBox() = default;
};// 具体产品:Windows 文本框
class WindowsTextBox : public TextBox {
public:void display() override { std::cout << "Windows 风格文本框" << std::endl; }
};// 具体产品:MacOS 文本框
class MacOSTextBox : public TextBox {
public:void display() override { std::cout << "MacOS 风格文本框" << std::endl; }
};// 抽象工厂
class GUIFactory {
public:virtual Button* createButton() = 0;virtual TextBox* createTextBox() = 0;virtual ~GUIFactory() = default;
};// 具体工厂:Windows 风格组件
class WindowsFactory : public GUIFactory {
public:Button* createButton() override { return new WindowsButton(); }TextBox* createTextBox() override { return new WindowsTextBox(); }
};// 具体工厂:MacOS 风格组件
class MacOSFactory : public GUIFactory {
public:Button* createButton() override { return new MacOSButton(); }TextBox* createTextBox() override { return new MacOSTextBox(); }
};// 使用示例
int main() {GUIFactory* factory = new MacOSFactory();Button* button = factory->createButton();button->render();  // 输出: MacOS 风格按钮TextBox* textBox = factory->createTextBox();textBox->display(); // 输出: MacOS 风格文本框delete button;delete textBox;delete factory;return 0;
}

4.4 三种工厂模式对比

4.5 工厂模式小结

  • 简单工厂:适合简单场景,但违背开闭原则。

  • 工厂方法:解决单一产品的扩展问题。

  • 抽象工厂:解决多产品族的创建问题,强调产品之间的关联性。

根据需求选择合适模式:若产品单一且可能扩展,用工厂方法;若需创建一组关联对象,用抽象工厂;若产品类型固定且简单,用简单工厂。

5. 总结

依赖倒置(DIP)、依赖注入(DI)、控制反转(IoC)和工厂模式是软件设计中紧密相关的概念,它们共同服务于代码的解耦和可维护性。

5.1 关联

  • 依赖倒置原则(Dependency Inversion Principle, DIP):高层模块不依赖低层模块,两者都依赖抽象(接口或抽象类)。该思想指导工厂模式、DI 和 IoC 的设计方向。

  • 控制反转(Inversion of Control, IoC):将对象的创建和生命周期管理权从程序内部转移给外部容器(如框架)。例如:依赖由外部容器(如工厂或框架)创建并注入,而不是直接创建依赖。工厂模式和依赖注入 DI 是实现 IoC 的具体方式。

  • 依赖注入(Dependency Injection, DI):通过构造函数、Setter 或接口,将依赖对象被动传递给使用方。是实现 IoC 的具体技术手段。工厂模式常用于生成这些依赖对象。

  • 工厂模式(Factory Pattern):封装具体对象创建逻辑,通过工厂类统一创建对象。是实现 IoC 的手段之一,隐藏实例化细节,支持 DIP 和 DI。是依赖注入 DI 和控制反转 IoC 的底层支撑。

四者共同目标是解耦代码,提升扩展性和可维护性。

5.2 示例全链路

// 1. 遵循 DIP:定义抽象接口
class IStorage { /* ... */ };// 2. 具体实现
class DatabaseStorage : public IStorage { /* ... */ };// 3. 工厂模式:封装对象创建
class StorageFactory {
public:static IStorage* createStorage() { return new DatabaseStorage(); }
};// 4. 依赖注入:通过构造函数传递对象
class UserService {
private:IStorage* storage;
public:UserService(IStorage* storage) : storage(storage) {}
};// 5. 控制反转:由工厂创建依赖,而非 UserService 内部创建
int main() {IStorage* storage = StorageFactory::createStorage();UserService userService(storage); // DI 注入userService.saveUser();delete storage;return 0;
}

文章转载自:Zijian/TENG

原文链接:依赖倒置 DIP、依赖注入 DI、控制反转 IoC 和工厂模式 - Zijian/TENG - 博客园

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

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

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

相关文章

UnitTest框架管理测试用例——python自动化测试

UnitTest框架 UnitTest是Python自带一个单元测试框架&#xff0c;常用它来做单元测试。 注意:对于测试来说&#xff0c;UnitTest框架的作用是 自动化脚本(用例代码)执行框架————(使用UnitTest框架来管理 运行多个测试用例的) 为什么使用UnitTest框架 能够组织多个用例去执…

Vue 过滤器深度解析与应用实践

文章目录 1. 过滤器概述1.1 核心概念1.2 过滤器生命周期 2. 过滤器基础2.1 过滤器定义2.2 过滤器使用 3. 过滤器高级用法3.1 链式调用3.2 参数传递3.3 动态过滤器 4. 过滤器应用场景4.1 文本格式化4.2 数字处理4.3 数据过滤 5. 性能优化与调试5.1 性能优化策略5.2 调试技巧 6. …

ngx_http_module_t

定义在 src\http\ngx_http_config.h typedef struct {ngx_int_t (*preconfiguration)(ngx_conf_t *cf);ngx_int_t (*postconfiguration)(ngx_conf_t *cf);void *(*create_main_conf)(ngx_conf_t *cf);char *(*init_main_conf)(ngx_conf_t *cf, void *conf);…

每日定投40刀BTC(9)20250312 - 20250315

定投截图 区块链相关新闻 BTC价格一度跌破8万美元 3月14日&#xff0c;BTC价格盘中跌破8万美元&#xff0c;最低报79,954.60美元&#xff0c;日内下跌1.34%&#xff0c;市场情绪一度转为谨慎 BTC价格波动背后的原因 经济环境变化、市场情绪波动以及政策监管动态是导致BTC价…

Matlab 汽车二自由度转弯模型

1、内容简介 Matlab 187-汽车二自由度转弯模型 可以交流、咨询、答疑 2、内容说明 略 摘 要 本文前一部分提出了侧偏角和横摆角速度作为参数。描述了车辆运动的运动状态&#xff0c;其中文中使用的参考模型是二自由度汽车模型。汽车速度被认为是建立基于H.B.Pacejka的轮胎模…

CentOS 6 YUM源切换成国内yum源

由于 CentOS 6 已于 2020 年 11 月进入 EOL&#xff08;End of Life&#xff09;&#xff0c;官方软件源已不再提供更新&#xff0c;因此你可能会遇到 yum makecache 命令失败的问题。以下是解决该问题的详细步骤&#xff1a; ### 解决方案 1. **备份原有 yum 源文件** bash …

Leetcode 3483. Unique 3-Digit Even Numbers

Leetcode 3483. Unique 3-Digit Even Numbers 1. 解题思路2. 代码实现 题目链接&#xff1a;3483. Unique 3-Digit Even Numbers 1. 解题思路 这一题其实是一个easy的题目&#xff0c;因为限制条件有限&#xff0c;最暴力的方法就是直接遍历一下100到999的全部数字&#xff…

《基于深度学习的高分卫星图像配准模型研发与应用》开题报告

目录 1. 选题的背景和意义 1.1 选题的背景 1.2 国内外研究现状 1.3 发展趋势 2&#xff0e;研究的基本内容 2.1 主要研究内容 &#xff08;1&#xff09;训练与测试数据集构建 &#xff08;2&#xff09;基于深度学习的高精度卫星影像配准模型 &#xff08;3&#xff0…

【Python 算法零基础 1.线性枚举】

我装作漠视一切&#xff0c;以为这样就可以不在乎 —— 25.3.17 一、线性枚举的基本概念 1.时间复杂度 线性枚举的时间复杂度为 O(nm)&#xff0c;其中 n是线性表的长度。m 是每次操作的量级&#xff0c;对于求最大值和求和来说&#xff0c;因为操作比较简单&#xff0c;所以 …

前端性能优化回答思路

前端性能优化是面试中经常涉及的一个话题&#xff0c;面试官通常希望了解你在实际项目中如何处理性能瓶颈&#xff0c;如何识别和优化性能问题。以下是一些前端性能优化的常见问题以及你可以用来回答的思路&#xff1a; 如何提升页面加载速度&#xff1f; 回答思路&#xff1…

02-Canvas-fabric.ActiveSelection

fabric.ActiveSelection fabric.ActiveSelection 用于表示当前选中的多个对象&#xff08;即多选状态&#xff09;。 当用户在画布上选择多个对象时&#xff0c;Fabric.js 会自动将这些对象包装在fabric.ActiveSelection 实例中&#xff0c;以便统一操作&#xff08;如移动、缩…

Leetcode——151.反转字符串中的单词

题解一 思路 最开始的想法是把一个字符串分为字符串数组&#xff0c;但是不知道一共有几个单词&#xff08;当时没想起来split()&#xff09;&#xff0c;所以选择了用ArrayList储存字符串&#xff0c;在输出时没有考虑ArrayList可以存储空字符串&#xff0c;所以最开始的输出…

Oracle检索数据

一、Oracle用户模式与模式 对象 1.概念 模式就是数据库对象的集合&#xff0c;数据库对象包括表、函数、索引、视图、过程。 2.示例模式scott SQL> select table_name from user_tables;TABLE_NAME ------------------------------------------------------------------…

Java学习------static、final、this、super关键字

1. static关键字 static修饰的变量叫做静态变量。当所有对象的某个属性的值是相同的&#xff0c;建议将该属性定义为静态变量&#xff0c;来节省内存的开销。静态变量在类加载时初始化&#xff0c;存储在堆中。static修饰的方法叫做静态方法。所有静态变量和静态方法&#xff…

一个简单的 **猜数字游戏** 的 C 语言例程

一个简单的 猜数字游戏 的 C 语言例程&#xff0c;代码包含详细注释&#xff0c;适合学习和练习基础语法&#xff1a; #include <stdio.h> #include <stdlib.h> #include <time.h> // 用于生成随机数种子int main() {int target, guess, attempts 0;srand…

Keepalived 多主模型与 LVS 高可用

一.Keepalived多主模型 Keepalived多主模型概念 如上图&#xff0c;keepalived主从架构性能损耗较严重&#xff0c;如果业务分类明确&#xff0c;则可以配置keepalived多主模型降低损耗&#xff0c;两台keepalived互为主备&#xff0c;如&#xff1a;订单业务走keepalived1&am…

RISCV虚拟化环境搭建

概要 本文记搭建 RISCV 虚拟化环境的流程。 整体架构 我们使用 QEMU 来模拟 RISCV 的各种硬件扩展环境&#xff0c;通过 QEMU 启动 Ubuntu 作为我们的 Host 来在 Host 之中通过 KVMTOOL 来运行 Guest&#xff0c;学习 RISCV 的虚拟化。 目前我的 X86_64 主机使用的是 Ubunt…

书摘 ASP.NET Core技术内幕与项目实战:基于DDD与前后端分离

IT行业的发展瞬息万变,新技术层出不穷,很多技术人员出于个人兴趣、个人职业发展等考虑而选择一些流行的新技术,他们会把各种复杂的架构模式、高精尖的技术都加入架构中,这增加了项目的复杂度、延长了交付周期、增加了项目的研发成本。有些技术并不符合公司的情况,最后项目…

神策数据接入 DeepSeek,AI 赋能数据分析与智能运营

在 AI 技术迅猛发展的浪潮下&#xff0c;神策数据正在加速推进人工智能在数据分析和智能运营领域的深度应用。近日&#xff0c;神策数据宣布全面接入 DeepSeek&#xff0c;为企业客户带来更加智能化、高效的数据分析与智能运营服务。这一举措展现了神策数据在人工智能方向的探索…

c++ 类和对象 —— 中 【复习笔记】

1. 类的默认成员函数 如果一个类什么成员都没有&#xff0c;简称空类。但实际上&#xff0c;任何类在不写成员时&#xff0c;编译器会自动生成6个默认成员函数&#xff08;用户未显式实现&#xff0c;编译器生成的成员函数&#xff09; 这6个成员函数可分为三类&#xff1a; …