【c++随笔13】多态
【c++随笔13】多态
- 多态性(Polymorphism)在面向对象编程中是一个重要概念,它允许以统一的方式处理不同类型的对象,并在运行时动态确定实际执行的方法或函数。
- 一、什么是多态性?
- 1、关键概念:C++的多态性
- 2、多态定义
- 3、没有 静态多态、动态多态
- 二、多态的详细介绍
- 1、多态的构成条件
- 2、覆盖(override)——重写
- 3、多态构成的两个意外
- 3.1、协变——构成多态
- 3.2、父虚子非虚——构成多态
- 4、析构函数的重写
- 1. 直接定义对象
- 2. 使用new操作符在堆上创建对象
- 3、结论:在堆上构建对象,且基类指针指向派生类的情况下,如果不加virtual,会发生内存泄漏,派生类不会析构。
- 5、final (C++11)
- 6、override(C++11)
- 7、重载、覆盖、隐藏的对比
- 三、抽象类
- 1、纯虚函数
- 2、 抽象类(abstract class)
- 3、抽象类指针
- 4、- 抽象类实例化?
- 5、接口继承(Interface Inheritance)和实现继承(Implementation Inheritance)是面向对象编程中的两种继承方式。
原创作者:郑同学的笔记
原创地址:https://zhengjunxue.blog.csdn.net/article/details/131858812
qq技术交流群:921273910
多态性(Polymorphism)在面向对象编程中是一个重要概念,它允许以统一的方式处理不同类型的对象,并在运行时动态确定实际执行的方法或函数。
一、什么是多态性?
1、关键概念:C++的多态性
我们查看《C++ Primer 第5版》第15.3章节 虚函数中的介绍(p537页)
OOP的核心思想是多态性(polymorphism)。多态性这个词源自希腊语,其含义是“多种形式”。我们把具有继承关系的多个类型称为多态类型,因为我们能使用这些类型的“多种形式”而无须在意它们的差异。引用或指针的静态类型与动态类型不同这一事实正是C++语言支持多态性的根本所在。
当我们使用基类的引用或指针调用基类中定义的一个函数时,我们并不知道该函数真正作用的对象是什么类型,因为它可能是一个基类的对象也可能是一个派生类的对象。如果该函数是虚函数,则直到运行时才会决定到底执行哪个版本,判断的依据是引用或指针所绑定的对象的真实类型。
另一方面,对非虚函数的调用在编译时进行绑定。类似的,通过对象进行的函数(虚函数或非虚函数)调用也在编译时绑定。对象的类型是确定不变的,我们无论如何都不可能令对象的动态类型与静态类型不一致。因此,通过对象进行的函数调用将在编译时绑定到该对象所属类中的函数版本上。
Note当且仅当对通过指针或引用调用虚函数时,才会在运行时解析该调用,也只有在这种情况下对象的动态类型才有可能与静态类型不同。
2、多态定义
我们依然查看《C++ Primer 第5版》第15章节末尾 术语表中的介绍(p576页)
多态性(polymorphism)当用于面向对象编程的范畴时,多态性的含义是指程序能通过引用或指针的动态类型获取类型特定行为的能力。
动态类型(dynamic type)对象在运行时的类型。引用所引对象或者指针所指对象的动态类型可能与该引用或指针的静态类型不同。基类的指针或引用可以指向一个派生类对象。在这样的情况中,静态类型是基类的引用(或指针),而动态类型是派生类的引用(或指针)。
静态类型(static type)对象被定义的类型或表达式产生的类型。静态类型在编译时是已知的。
3、没有 静态多态、动态多态
我们看网上有很多资料介绍动态时,都会提到多态分为静态多态(比如函数重载等)和动态多态,而当我们看了上面书中的定义和介绍后会明白,网上的说法是有问题的。
在c++领域:
- 只有多态、不区分静态多态和动态多态;
- 网上说的c++动态多态就是指的c++中的多态;
- 网上说的静态多态,不符合《C++ Primer 第5版》多态的概念;
- 静态多态按照《C++ Primer 第5版》中书写demo,无法实现多态;
二、多态的详细介绍
动态多态性是在运行时确定方法或函数的调用,根据实际对象的类型进行动态绑定。这种多态性通过虚函数和基类指针或引用来实现。
简单来说,
多态: 就是多种形态,不同的对象去完成同样的事情会产生不同的结果。
举个例子:就拿购票系统来说,不同的人对于购票这个行为产生的结果就是不同的,学生购票时购买的是半价票,普通人购票的时候购买的是全价票。
1、多态的构成条件
继承中想要构成多态,必须满足以下两个条件:
① 必须是子类的虚函数重写成父类函数(重写:三同 + 虚函数)
② 必须是父类的指针或者引用去调用虚函数。
- 三同指的是:同函数名、同参数、同返回值。
- 虚函数:即被 virtual 修饰的类成员函数。
- 指针调用
#include <iostream>
using namespace std;class Person {
public:Person(const char* name): _name(name) {}// 虚函数virtual void BuyTicket() {cout << _name << ": " << "Person-> 买票 全价 100¥" << endl;}protected:string _name;
};class Student : public Person {
public:Student(const char* name): Person(name) {}// 虚函数 + 函数名/参数/返回 -> 重写(覆盖)virtual void BuyTicket() {cout << _name << ": " << "Student-> 买票 半价 50¥" << endl;}
};class Soldier : public Person {
public:Soldier(const char* name): Person(name) {}// 虚函数 + 函数名/参数/返回 -> 重写(覆盖)virtual void BuyTicket() {cout << _name << ": " << "Soldier-> 优先买预留票 全价 100¥" << endl;}
};/* 接收身份 */
void Pay(Person* ptr) {ptr->BuyTicket(); // 到底是谁在买票,取决于传来的是谁delete ptr;
}int main()
{Person* p1 = new Person("小明爸爸");Student* stu = new Student("小明");Soldier* so = new Soldier("小明爷爷");Pay(p1);Pay(stu);Pay(so);return 0;
}
输出
- 引用调用
/* 接收身份 */
void Pay(Person& ptr) {ptr.BuyTicket(); // 到底是谁在买票,取决于传来的是谁
}int main()
{Person p1("小明爸爸");Student stu("小明");Soldier so("小明爷爷");Pay(p1);Pay(stu);Pay(so);return 0;
}
2、覆盖(override)——重写
我们依然查看《C++ Primer 第5版》第15章节末尾 术语表中的介绍(p576页)
- 覆盖(override)派生类中定义的虚函数如果与基类中定义的同名虚函数有相同的形参列表,则派生类版本将覆盖基类的版本。
覆盖也被有的文章叫做”重写“。用 virtual 虚函数,并且做到函数名、参数和返回值相同,就能够达到 “重写” 的效果:
重写是为了将一个已有的事物进行某些改变以适应新的要求。
重写是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变。 即:“外壳不变,核心重写。”
3、多态构成的两个意外
刚才说了,三同+虚函数,就能达到重写的效果(也就是多态)。但是,还有两个意外,也能达成多态的效果。
3.1、协变——构成多态
-
C++中的协变(Covariance)指的是派生类可以返回基类中相同函数签名的返回类型的子类型。
-
在C++中,当一个虚函数在基类中使用了virtual关键字声明为虚函数时,派生类可以对该虚函数进行重写,并且在派生类中返回类型可以是基类返回类型的子类型。这种返回类型的子类型关系称为协变。
协变的类型必须是父子关系。
观察下面的代码,并没有达到 “三同” 的标准,它的返回值是不同的,但依旧构成多态:
class A {};
class B : public A {};class Person {
public:virtual A* f() {cout << "virtual A* Person::f()" << endl;return nullptr;}
};class Student : public Person {
public:virtual B* f() {cout << "virtual B* Student:::f()" << endl;return nullptr;};
};int main(void)
{Person p;Student s;Person* ptr = &p;ptr->f();ptr = &s;ptr->f();return 0;
}
输出
当class A、class B是父子关系时,就不能协变:
3.2、父虚子非虚——构成多态
现在来讲第二个例外。
- 父类的虚函数没了无法构成多态:
- 但是,子类的虚函数没了却能构成多态:
#include <iostream>
using namespace std;class A {};
class B : public A {};class Person {
public:virtual A* f() {cout << "virtual A* Person::f()" << endl;return nullptr;}
};class Student : public Person {
public:B* f() {cout << "virtual B* Student:::f()" << endl;return nullptr;};
};int main(void)
{Person p;Student s;Person* ptr = &p;ptr->f();ptr = &s;ptr->f();return 0;
}
输出
4、析构函数的重写
1. 直接定义对象
#include <iostream>
using namespace std;class Person {
public:~Person() { //不加virtual// virtual ~Person() { //加virtualcout << "~Person()" << endl;}
};class Student : public Person {
public:~Student() {cout << "~Student()" << endl;}
};int main(void)
{Person p;Student s;return 0;
}
-
加virtual输出
-
不加virtual输出
2. 使用new操作符在堆上创建对象
#include <iostream>
using namespace std;class Person {
public:~Person() { //不加virtual//virtual ~Person() { //加virtualcout << "~Person()" << endl;}
};class Student : public Person {
public:~Student() {cout << "~Student()" << endl;}
};int main(void)
{cout << "=================不加virtual======================\n";Person *ptr = new Person();delete ptr;cout << "=======================================\n";Student *ptr2 = new Student();delete ptr2;cout << "=======================================\n";Person *ptr3 = new Student();delete ptr3;return 0;
}
-
不加virtual
-
加virtual
刚才我们看到了,如果这里不加 virtual,~Student 是没有调用析构的。
这其实是非常致命的,是不经意间会发生的内存泄露。
3、结论:在堆上构建对象,且基类指针指向派生类的情况下,如果不加virtual,会发生内存泄漏,派生类不会析构。
5、final (C++11)
在C++中,final是一个关键字,用于修饰类、函数或虚函数,具有不同的作用。
- 修饰类:使用final关键字修饰类时,表示该类是最终类,不能被其他类继承。例如:
class Base final {// ...
};class Derived : public Base { // 错误,Derived不能继承自final类Base// ...
};
在上述示例中,Base类被声明为final,因此Derived类不能继承自Base类。
- 修饰函数:使用final关键字修饰成员函数时,表示该函数是最终版本,不能被派生类重写。例如:
class Base {
public:virtual void func() final {// ...}
};class Derived : public Base {
public:void func() override { // 错误,无法重写被声明为final的函数// ...}
};
在上述示例中,Base类中的func()函数被声明为final,因此Derived类无法对其进行重写。
- 修饰虚函数:与修饰普通成员函数类似,使用final关键字修饰虚函数时,表示该虚函数是最终版本,不能被派生类重写。例如:
class Base {
public:virtual void func() final {// ...}
};class Derived : public Base {
public:void func() override { // 错误,无法重写被声明为final的虚函数// ...}
};
在上述示例中,Base类中的虚函数func()被声明为final,因此Derived类无法对其进行重写。
通过使用final关键字,可以显式地阻止类、函数或虚函数被继承、重写或覆盖,从而提高程序的安全性和可靠性。
6、override(C++11)
override是C++11引入的关键字,用于显式地标记派生类中对基类虚函数的重写。它的主要作用是增加代码的可读性和可维护性,并提供编译器的静态检查,避免错误的重写行为。
在C++中,当派生类要重写基类的虚函数时,可以使用override关键字进行标记。通过使用override关键字,可以确保派生类的函数签名与基类的虚函数完全匹配,否则编译器会发出错误。这有助于及时发现错误的重写行为。
以下是使用override关键字的示例:
class Base {
public:virtual void func() const {// ...}
};class Derived : public Base {
public:void func() const override {// ...}
};
在上述示例中,Base类中的虚函数func()被定义为virtual void func() const,而在Derived类中,重写的函数也被定义为void func() const,并使用override关键字进行标记。如果Derived类的函数签名与基类的虚函数不匹配,或者没有正确使用override关键字,编译器将会报错。
7、重载、覆盖、隐藏的对比
三、抽象类
1、纯虚函数
我们依然查看《C++ Primer 第5版》第15章节末尾 术语表中的介绍(p576页)
- 纯虚函数(pure virtual)在类的内部声明虚函数时,在分号之前使用了=0。一个纯虚函数不需要(但是可以)被定义。含有纯虚函数的类是抽象基类。如果派生类没有对继承而来的纯虚函数定义自己的版本,则该派生类也是抽象的。
纯虚函数是通过在函数声明后面加上= 0来声明的,表示该函数没有实现,派生类必须重写它。
virtual void pureVirtualFunction() = 0;
在上述示例中,纯虚函数pureVirtualFunction()。
- 纯虚函数是否可以实现?
纯虚函数也是可以实现的:
/* 抽象类 */
class Car {
public:// 实现没有价值,因为压根没有对象会调用它virtual void Drive() = 0 { // 纯虚函数cout << "Drive()" << endl; }
};
2、 抽象类(abstract class)
- 包含纯虚函数的类,就是 抽象类(abstract class),也叫接口类。
class AbstractClass {
public:virtual void pureVirtualFunction() = 0;
};
在上述示例中,AbstractClass是一个抽象类,它具有一个纯虚函数pureVirtualFunction()。派生类必须重写这个函数。
抽象类可以包含纯虚函数(没有实现)和带有实现的函数
3、抽象类指针
虽然父类是抽象类不能定义对象,但是可以定义指针。
定义指针时如果 new 父类对象因为是纯虚函数,自然是 new 不出来的,但是可以 new 子类对象:
#include <iostream>
using namespace std;/* 抽象类 */
class Car {
public:virtual void Drive() = 0;
};class Benz : public Car {
public:virtual void Drive() {cout << "Benz-舒适" << endl;}
};int main(void)
{Car* pBenz1 = new Benz;pBenz1->Drive();Benz* pBenz2 = new Benz;pBenz2->Drive();return 0;
}
4、- 抽象类实例化?
抽象类不能实例化出对象,子类即使在继承后也不能实例化出对象,除非子类重写。
5、接口继承(Interface Inheritance)和实现继承(Implementation Inheritance)是面向对象编程中的两种继承方式。
接口继承指的是一个类从一个或多个接口中继承方法声明,但并不继承这些方法的具体实现。接口只包含纯虚函数(在C++中使用纯虚函数定义接口)或者抽象方法(在其他语言中)。通过接口继承,一个类可以实现多个接口,从而表达出它具备了多个行为或功能。
实现继承指的是子类从父类中继承方法声明和实现。实现继承建立了类的层次结构,允许子类继承并重用父类的代码。子类可以通过继承父类的属性和方法,并且可以根据需要添加新的属性和方法,甚至可以重写父类的方法来改变其行为。
- 普通函数的继承是一种实现继承,子类继承了父类函数,可以使用函数,继承的是函数的实现。
- 虚函数的继承是一种接口继承,子类继承的是父类虚函数的接口,目的是为了重写,
- 达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数。
- 出现虚函数就是为了提醒你重写的,以实现多态。如果虚函数不重写,那写成虚函数就没价值了。
相关文章:

【c++随笔13】多态
【c随笔13】多态 多态性(Polymorphism)在面向对象编程中是一个重要概念,它允许以统一的方式处理不同类型的对象,并在运行时动态确定实际执行的方法或函数。一、什么是多态性?1、关键概念:C的多态性2、多态定…...

数据结构【DS】图的应用
图的连通性问题 最少边数 最多边数 无向图非连通 𝒎𝟎 𝒎𝒏−𝟐∗(𝒏−𝟏)/𝟐 无向图连通 𝒎𝒏−𝟏 𝒎𝒏∗(&#…...
图像滤波处理
滤波处理是图像处理中常用的技术之一,用于去除图像中的噪声、平滑图像、边缘检测等。以下是几种常见的滤波处理方法: 1. 均值滤波 (Mean Filtering) 原理: 均值滤波使用一个固定大小的滤波器,在图像上滑动并取周围像素的平均值来…...

中间件安全:Apache 目录穿透.(CVE-2021-41773)
中间件安全:Apache 目录穿透.(CVE-2021-41773) Apache 的 2.4.49、2.4.50 版本 对路径规范化所做的更改中存在一个路径穿越漏洞,攻击者可利用该漏洞读取到Web目录外的其他文件,如系统配置文件、网站源码等,…...
苍穹外卖--菜品分页查询
设计DTO类 Data public class DishPageQueryDTO implements Serializable {private int page;private int pageSize;private String name;private Integer categoryId; //分类idprivate Integer status; //状态 0表示禁用 1表示启用}设计VO类 Data Builder NoArgsConstructor…...

JS原生-弹框+阿里巴巴矢量图
效果: 代码: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&q…...

vscode c++ 报错identifier “string“ is undefined
vscode c 报identifier “string” is undefined 问题 新装了电脑, 装好vsc和g等, 发现报错 但开头并没问题 解决 shiftctrlp选择 C/C Edit:COnfigurations (JSON)自动生成打开 c_cpp_properties.json添加g路径等 "cStandard": "c11","cppStanda…...
CocoaPods podfile 文件配置
记录一下关于 CocoaPods podfile 文件配置 指定源(Source) 默认情况下,在全局级别指定的源将按照依赖项匹配指定的顺序进行搜索。 对于特定的依赖,可以单独指定依赖源: pod PonyDebugger, :source > https://github.com/CocoaPods/Specs.git使用字库…...

Python大数据之linux学习总结——day10_hive调优
hive调优 hive调优hive命令和参数配置1.hive数据压缩压缩对比开启压缩 2.hive数据存储[练习]行列存储原理存储压缩比拓展dfs -du -h 3. fetch抓取4. 本地模式5. join的优化操作6. 列裁剪7. 分区裁剪8. group by 操作9. count(distinct)10. 笛卡尔积11. 动态分区[练习]12. 如何调…...

原理Redis-动态字符串SDS
动态字符串SDS Redis中保存的Key是字符串,value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。 不过Redis没有直接使用C语言中的字符串,因为C语言字符串存在很多问题: 获取字符串长度的需要通过运算非二进制安全…...
axios的封装之axios是基于什么封装的?
axios的封装_axios是基于什么封装的 axios是基于JavaScript的XMLHttpRequest 和 Promise 对象进行封装的使用axios发送GET请求的示例axios 拦截器 axios的封装_axios是基于什么封装的 axios是基于JavaScript的XMLHttpRequest 和 Promise 对象进行封装的 在浏览器中ÿ…...
应用软件安全编程-20生成强随机数
JavaAPI 提 供 了java,util.Random 类 来 实 现PRNG。 这 个 PRNG 是可移植和可重复的。因此,如 果 两 个java.util.Random 类的实例使用了相同的种子,会在所有的 Java 实 现 中 生 成 相 同 的 数 值 序 列 。 在应用初始化时,或者在每…...

【C语言.oj刷题】有序#整型矩阵元素查找##{思路+C源码}
目录 题目信息 题目分析: 法一: 遍历二维数组(低效) 思路 源码 局限性 法二: 对每一行二分查找(有所提效) 思路 源码 局限性 法三: 利用一切有利条件使用二分查找 思路 …...

rabbitmq默认交换机锁绑定的routingkey-待研究
例如这个是我的一个消息队列,它默认绑定的交换机是 什么类型呢? 看到这个图,感觉应该是一个默认的交换机,因为是default exchange 于是来到交换机来看看其他默认的交换机: 这里可以看到默认的交换机是direct(应该没…...

【计算思维】蓝桥杯STEMA 科技素养考试真题及解析 4
1、下列哪个选项填到填到下图空缺处最合适 A、 B、 C、 D、 答案:D 2、按照如下图的规律摆放正方形,第 5 堆正方形的个数是 A、13 B、14 C、15 D、16 答案:D 3、从右面观察下面的立体图形,看到的是 A、 B、 C、 D、 答…...

基于STM32CubeMX和keil采用RTC时钟周期唤醒和闹钟实现LED与BEEP周期开关
文章目录 前言1. RTC概念1.1 RTC的时钟信号源1.2 预分频器1.3 实时时钟与日历数据1.4 周期性自动唤醒1.5 可编程闹钟 2. RTC相关中断3. STM32CubeMX配置3.1 时钟配置3.2 引脚配置3.3 RTC配置3.3.1 模式选择3.3.2 RTC基本参数配置3.3 中断配置 4. 代码编写总结 前言 RTC的功能有…...

Virtual安装centos后,xshell连接centos
1. 网络使用Host-Only模式动态分配IP,点确定后,centos 上运行 system restart network ,使用ifconfig查看新的ip,XShell可以直接连上centos, 但是由于使用的是Host-Only模式,centos不能访问网络,…...

Taro.navigateTo 使用URL传参数和目标页面参数获取
文章目录 1. Taro.navigateTo 简介2. 通过 URL 传递参数3. 目标页面参数获取4. 拓展与分析4.1 拓展4.2 URL参数的类型4.3 页面间通信 5. 总结 🎉欢迎来到Java学习路线专栏~Taro.navigateTo 使用URL传参数和目标页面参数获取 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x…...

Unity Meta Quest 一体机开发(七):配置玩家 Hand Grab 功能
文章目录 📕教程说明📕玩家物体配置 Hand Grab Interactor⭐添加 Hand Grab Interactor 物体⭐激活 Hand Grab Visual 和 Hand Grab Glow⭐更新 Best Hover Interactor Group 📕配置可抓取物体(无抓取手势)⭐刚体和碰撞…...

我又开始贩卖焦虑了,机器视觉兄弟们,打工这生意盘不活了?让人逃离北上广深,是毒鸡汤吗?
我想大多数人和我想的一样,不要质疑自己的出身,也不必用一生去改变出身而获得融入感,思想富足这是我们留给自己一生最珍贵的礼物。也许一线城市容不下肉身,二三线城市容不下灵魂。那我回到生我养我的十八线小县城,这不…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...