C++进阶——多态

ʕ • ᴥ • ʔ

づ♡ど

 🎉 欢迎点赞支持🎉

个人主页:励志不掉头发的内向程序员;

专栏主页:C++语言;


文章目录

前言

一、多态的概念

二、多态的定义及实现

2.1、多态的构成条件

(1)虚函数

(2)虚函数的重写/覆盖

 (3)实现多态的两个必须重要条件

(4)虚函数重写的一些其他问题

(5)override 和 final 关键字

(6)重载/重写/隐藏的对比

三、纯虚函数和抽象类

四、多态的原理

4.1、虚函数表指针

4.2、多态的原理

(1)多态是如何实现的

(2)动态绑定与静态绑定

(3)虚函数表

总结


前言

学习了继承以后,我们接着来看看我们继承的延伸—多态,多态的内容也是非常的多,我们大家得仔细学习,我们想要成为 C++ 大佬是无论如何都绕不开我们继承和多态的。


一、多态的概念

多态通俗来说就是多种形态。多态分为编译时多态(静态多态)和运行时多态(动态多态),这里我们重点讲运行时多态。

编译时多态主要就是我们前面讲的函数重载和函数模板,他们通过传不同类型的参数就可以调用不同的函数,通过参数的不同达到多种形态,之所以叫编译时多态,是因为他们实参传给形参的参数匹配是在编译时完成的,我们把编译时一般归为静态,运行时归为动态。

运行时多态,具体点就是去完成某个行为(函数),可以传不同的对象就会完成不同的行为,就达到多种形态。比如吃饭这个行为,当中国人吃饭时,拿的是筷子调羹;美国人吃饭时,拿的是刀和叉子;印度人吃饭时直接用手等。再比如同样是动物叫的一个行为(函数),传猫对象过去就是 "喵喵";狗对象过去就是 "汪汪"。

二、多态的定义及实现

2.1、多态的构成条件

(1)虚函数

类成员函数前面加 virtual 修饰,那么这个成员函数就被称为虚函数。注意非成员函数不能加 virtual 修饰。

class Person
{
public:// 虚函数virtual void EatFood(){cout << "用餐具吃饭" << endl;}
};

(2)虚函数的重写/覆盖

虚函数的重写/覆盖:派生类中有一个跟基类完全相同的虚函数,即派生类虚函数与基类虚函数的返回值、函数名字、参数列表完全相同(简称 "三同"),称派生类的虚函数重写了基类的虚函数。

class Person
{
public:virtual void EatFood(){cout << "用餐具吃饭" << endl;}
};class Chinese : public Person
{
public:// 此处构成虚函数的覆盖/重写virtual void EatFood(){cout << "用筷子吃饭" << endl;}
};

我们发现上面的代码在重写我们的虚函数时,派生类的虚函数前也加了 virtual 关键字。但其实派生类的虚函数在不加 virtual 关键字时,也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是这样写不是非常规范,不建议这样使用。我们要明白虚函数的具体写法,而不是看前面有没有 virtual。

class Person
{
public:virtual void EatFood(){cout << "用餐具吃饭" << endl;}
};class Chinese : public Person
{
public:// 此处依然构成虚函数的覆盖/重写void EatFood(){cout << "用筷子吃饭" << endl;}
};

这样写也可以,但是强烈不建议。

 (3)实现多态的两个必须重要条件

我们在学习完我们上面的内容,我们结合上面内容来看看实现多态的两个重要条件。

  • 必须是基类的指针或者引用调用虚函数。
  • 被调用的函数必须是虚函数,并且完成了虚函数重写/覆盖。

我们在继承那一章节学习了切片,子类和子类的指针引用可以赋值给我们父类以达到切片的效果,但是反过来就不太行,所以这里的函数就得调用基类的指针或者引用,这样我们不管是传父类还是子类(子类会被父类切片)都可以传参。

同时子类必须对父类的虚函数进行重写/覆盖,不然我们不管调用父类的函数还是子类的函数都是一样的效果,也没办法实现多态的不同形态的效果。

class Person
{
public:// 虚函数virtual void EatFood(){cout << "用餐具吃饭" << endl;}
};class Chinese : public Person
{
public:// 基类虚函数的重写/覆盖virtual void EatFood(){cout << "用筷子吃饭" << endl;}
};void Func(Person* ptr)
{// 这⾥可以看到虽然都是Person指针Ptr在调⽤EatFood// 但是跟ptr没关系,⽽是由ptr指向的对象决定的。ptr->EatFood();
}int main()
{Person ps;Chinese ce;Func(&ps);Func(&ce);return 0;
}

看上去我们都是调用的同一个函数,但其实这个函数的输出是和我们传的 ptr 的类型是有关联的,指向父类调用父类,指向子类调用子类。

我们传给函数 Person 的 引用也是可以的。

void Func(Person& ptr)
{ptr.EatFood();
}

但是如果我们破环掉这两个必须的重要条件,我们的程序就无法实现多态的效果了。

破坏第一条,我们传值给 ptr。

void Func(Person ptr)
{ptr.EatFood();
}

或者破坏第二条,我们不去给我们的从父类继承下来的虚函数进行重写。

class Chinese : public Person
{
public:
};void Func(Person& ptr)
{ptr.EatFood();
}

我们的多态都会失效。

当然,我们多个子类之间也可以实现多态的条件。

class Animal
{
public:virtual void talk() const{}
};class Dog : public Animal
{
public:virtual void talk() const{cout << "汪汪" << endl;}
};class Cat : public Animal
{
public:virtual void talk() const{cout << "(>^ω^<)喵" << endl;}
};class Mouse : public Animal
{
public:virtual void talk() const{cout << "吱吱" << endl;}
};void letsHear(const Animal& animal)
{animal.talk();
}int main()
{Cat cat;Dog dog;Mouse mouse;letsHear(cat);letsHear(dog);letsHear(mouse);return 0;
}

(4)虚函数重写的一些其他问题

协变(了解)

派生类重写基类虚函数时,与基类函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用,称为协变。协变的实际意义并不大,所以我们了解一下即可。

class A{};class B : public A {};class Person
{
public:virtual A* EatFood(){cout << "用餐具吃饭" << endl;return nullptr;}
};class Chinese : public Person
{
public:virtual B* EatFood(){cout << "用筷子吃饭" << endl;return nullptr;}
};void Func(Person& ptr)
{// 这⾥可以看到虽然都是Person指针Ptr在调⽤EatFood// 但是跟ptr没关系,⽽是由ptr指向的对象决定的。ptr.EatFood();
}int main()
{Person ps;Chinese ce;Func(ps);Func(ce);return 0;
}

我们的虚函数的返回值不相同,父类对象返回一个父类指针或引用,子类对象返回一个子类指针或引用。同样可以实现多态的效果,我们就称为协变。

析构函数的重写

基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加 virtual 关键字,都与基类的析构函数构成重写。虽然基类与派生类析构函数名字不同看起来不符合重写规则,实际上编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成 destructor,所以基类的析构函数加了 virtual 修饰,派生类的析构函数就构成重写了。

class A
{
public:virtual ~A(){cout << "~A()" << endl;}
};class B : public A 
{
public:~B(){cout << "~B()->delete:" << _p << endl;delete _p;}
protected:int* _p = new int[10];
};

我们这里可以看到,我们 B 的析构名字和 A 的不一样,按道理来说是不会构成重写的,但实际上它们是构成的,因为我们编译器会把析构的名字统一处理成 destructor,所以此时它们名字相同了就构成了重写了。

我们要让析构函数变成虚函数的原因是因为当我们创建了一个父类的指针,有可能指向父类对象,也有可能指向子类对象。如果指向子类对象,此时我们调用父类的 delete 就会无法析构子类的那一部分。

int main()
{// 没问题A* p1 = new A;delete p1;// 有问题A* p2 = new B;delete p2;return 0;
}

我们 delete p2 时我们其实是期望它调用子类的析构函数的,不然就会出现问题。所以我们就得实现虚函数的重写去让我们指向父类调用父类,指向子类调用子类。

(5)override 和 final 关键字

从上面可以看出,C++ 对函数重写的要求比较严格,但是有些情况下由于疏忽,比如函数名写错参数写错等导致无法构成重写,而这种错误在编译期间是不会报出的,而在程序运行时没有得到预期结果去 debug 就会得不偿失,因此 C++11 提供了 override,可以帮助用户检测是否重写。如果我们不想让派生类重写这个虚函数,那么可以用 final 去修饰。

class Car 
{
public:virtual void Dirve(){}
};class Benz :public Car {
public:virtual void Drive() override { cout << "Benz-舒适" << endl;}
};

此时我们的 Dirve 由于写错了而导致无法构成重写,此时我们在后面加入的 override 就起作用了。

当然,如果有基类的成员函数不想被重写,加入 final 就不能被继承了。

class Car
{
public:virtual void Drive() final {}
};class Benz :public Car
{
public:virtual void Drive() { cout << "Benz-舒适" << endl; }
};

(6)重载/重写/隐藏的对比

它们都有函数之间的关系,相似性极高。

三、纯虚函数和抽象类

在虚函数的后面写上 =0,则这个函数为纯虚函数,纯虚函数不需要定义实现(实现没啥意义,因为要被派生类重写,但是语法上可以实现),只要声明即可。包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象,如果派生类继承后不重写纯虚函数,那么派生类也是抽象类。纯虚函数某种程度上强制了派生类重写虚函数,因为不重写实例化不出对象。

class Car
{
public:virtual void Drive() = 0;
};class Benz :public Car
{
public:virtual void Drive(){cout << "Benz-舒适" << endl;}
};class BMW :public Car
{
public:virtual void Drive(){cout << "BMW-操控" << endl;}
};

此时我们 Car 中的 Drive 就是我们的纯虚函数,Car 就是我们的抽象类。我们的抽象类无法实例出对象。

int main()
{// 编译报错⽆法实例化抽象类Car car;return 0;
}

正是因为无法实例化出对象,所以我们没有必要去实现我们的纯虚函数,因为无法调用。

如果我们的子类不去实现我们的纯虚函数,我们的类依旧是抽象类,因为依旧会继承我们的父类的纯虚函数。但是我们的子类也无法实例化出对象了。

class Benz :public Car
{
public:
};int main()
{Car* pBenz = new Benz;pBenz->Drive();return 0;
}

所以说我们的纯虚函数的作用就是强制我们的派生类去实现这个纯虚函数,不然就无法调用。当我们实现了,就能够成功调用了。

int main()
{Car* pBenz = new Benz;pBenz->Drive();Car* pBMW = new BMW;pBMW->Drive();return 0;
}

四、多态的原理

4.1、虚函数表指针

我们来算一下下面代码的运行结果。

class Base
{
public:virtual void Func1(){cout << "Func1()" << endl;}
protected:int _b = 1;char _ch = 'x';
};int main()
{Base b;cout << sizeof(b) << endl;return 0;
}

我们大家一看,这不是很简单吗,Base 类中有一个 int 整型,char 整型,所以就是 8 字节秒了。实则不然。

我们的答案是 12 字节,我们通过调试发现,除了 _b 和 _c 成员,还多一个 _vfptr 放在对象的前面(有的平台可能放对象后面,和平台有关)。

对象中的这个指针我们叫做虚函数表指针(v 表示 virtual,f 表示 function)。一个含有虚函数的类中都至少有一个虚函数表指针,因为一个类所有的虚函数的地址要被放到这个类对象的虚函数中,虚函数表也称为虚表。严格来说,它是一个函数指针数组。

我们尝试多加几个虚函数来看看效果。
class Base
{
public:virtual void Func1(){cout << "Func1()" << endl;}virtual void Func2(){cout << "Func2()" << endl;}virtual void Func3(){cout << "Func3()" << endl;}protected:int _b = 1;char _ch = 'x';
};

4.2、多态的原理

(1)多态是如何实现的

从底层的角度 Func 函数中的 ptr->BuyTicket(),是如何作为 ptr 指向 Person 对象调用 Person::BuyTicket,ptr 指向 Student 对象调用 Student::BuyTicket 的呢?

class Person 
{
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }
private:string _name;
};class Student : public Person 
{
public:virtual void BuyTicket() { cout << "买票-打折" << endl; }
private:string _id;
};class Soldier : public Person 
{
public:virtual void BuyTicket() { cout << "买票-优先" << endl; }
private:string _codename;
};void Func(Person* ptr)
{// 这⾥可以看到虽然都是Person指针Ptr在调⽤BuyTicket// 但是跟ptr没关系,⽽是由ptr指向的对象决定的。ptr->BuyTicket();
}int main()
{// 其次多态不仅仅发⽣在派⽣类对象之间,多个派⽣类继承基类,重写虚函数后// 多态也会发⽣在多个派⽣类之间。Person ps;Student st;Soldier sr;Func(&ps);Func(&st);Func(&sr);return 0;
}

通过下图我们可以看到,满足多态条件后,底层不再是编译时通过调用对象确定函数的地址,而是运行时到指向的对象的虚表中确定对应的虚函数的地址,这样就实现了指针或引用指向基类就调用基类,指向派生类就调用派生类对应的虚函数。

由于切片,导致我们传递给 Func 函数的每一个类都只有 Person 的那一部分,此时我们编译器就是更具我们的虚函数表指针中的地址找到我们不同的函数位置,从而形成多态行为的。

这张图就是我们 Person 类传递给 ptr,ptr 指向 Person,此时我们就会调用 Person 的 _vfptr 去找寻关于 BuyTicket 函数的指针。

这张图是我们 Student 类传递给 ptr,在这之间进行了切片操作,然后 ptr 指向 Student 中属于 Person 的那一部分,此时我们就会调用 Student 中的 Person 的 _vfptr 去找寻关于 BuyTicket 函数的指针。

(2)动态绑定与静态绑定

  • 对不满足多态条件(指针或者引用 + 调用虚函数)的函数调用是在编译时绑定的,也就是编译时确定调用函数的地址,叫做静态绑定
  • 满足多态条件的函数调用是在运行时绑定,也就是在运行时指向对象的虚函数表中找到调用函数的地址,也叫做动态绑定。

我们可以从汇编来看看。

// ptr是指针+BuyTicket是虚函数满⾜多态条件。
// 这⾥就是动态绑定,编译在运⾏时到ptr指向对象的虚函数表中确定调⽤函数地址
ptr->BuyTicket();
00EF2001 mov eax, dword ptr[ptr]
00EF2004 mov edx, dword ptr[eax]
00EF2006 mov esi, esp
00EF2008 mov ecx, dword ptr[ptr]
00EF200B mov eax, dword ptr[edx]
00EF200D call eax
// BuyTicket不是虚函数,不满⾜多态条件。
// 这⾥就是静态绑定,编译器直接确定调⽤函数地址
ptr->BuyTicket();
00EA2C91 mov ecx, dword ptr[ptr]
00EA2C94 call Student::Student(0EA153Ch)

(3)虚函数表

  • 基类对象的虚函数表中存放基类所有的虚函数的地址。同类型的对象共用一张虚表,不同类型的对象各自有独立的虚表,所以基类和派生类有各自独立的虚表。
  • 派生类由两部分构成,继承下来的基类和自己的成员,一般情况下,继承下来的基类中有虚函数表指针,自己就不会再生成虚函数表指针。但是要注意这里继承下来的基类部分虚函数表指针和基类对象的虚函数表指针不是同一个,就像基类对象的成员和派生类对象中的基类对象成员也是相互独立的。
  • 派生类中重写基类的虚函数,派生类的虚函数表中对应的虚函数就会被覆盖成派生类重写的虚函数地址。
  • 派生类的虚函数表中包含:(1)基类的虚函数地址;(2)派生类重写的虚函数地址完成覆盖;(3)派生类自己的虚函数地址三个部分。
  • 虚函数表本质是一个存虚函数指针的指针数组,一般情况这个数组最后面放了一个0x00000000 标记(这个 C++并没有进行规定,各个编译器自行定义的,vs 系列编译器会在后面放,g++系列编译不会放)
  • 虚函数和普通函数一样,编译好后是一段指令,都是存在代码段的,至少虚函数的地址又存在虚表中。
  • 虚函数表存放的位置严格来说并没有标准答案 C++ 标准并没有规定,在 vs 中存在代码段(常量区)

我们每个基类和派生类如果有虚函数都有一张虚表,但是如果它们类型相同,那它们使用的虚表也是相同的。我们子类继承的父类的虚函数表,但是它们不是同一个虚函数,而是独立的。

如果我们的子类没有重写我们的父类,那我们子类的虚函数表就会在自己的虚函数表中从父类的虚函数表拷贝一份放到子类中属于父类的那一部分虚函数表中。

如果我们有重写,那我们重写的内容就会把基类对应位置进行覆盖,然后写上自己的函数内容。


总结

以上便是我们多态的全部内容,继承和多态的产生,使我们 C++ 的代码的层次更加的多样,在我们以后的大型项目中会经常遇见,我们这里一定得多多学习了解。

🎇坚持到这里已经很厉害啦,辛苦啦🎇

ʕ • ᴥ • ʔ

づ♡ど

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

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

相关文章

Swift 语法学习指南 - 与 Kotlin 对比

Swift 语法学习指南 - 与 Kotlin 对比 本指南专为有 Android/Kotlin 开发经验的开发者设计&#xff0c;通过对比学习快速掌握 Swift 语法 目录 语言基础对比变量与常量数据类型函数定义类与结构体继承与协议可选类型集合类型控制流闭包与Lambda扩展与Extension错误处理内存管理…

嵌入式C语言笔记十七——构造数据类型

一.结构体&#xff1a;1.类型定义&#xff1a;struct 结构体名 {数据类型1 成员变量1;数据类型2 成员变量2;数据类型3 成员变量3;... };struct student {char name[32];char sex;int age;int score; };2.结构体变量定义&#xff1a;存储类型 数据类型 变量名;3.结构体元素初始化…

深入实践G1垃圾收集器调优:Java应用性能优化实战指南

深入实践G1垃圾收集器调优&#xff1a;Java应用性能优化实战指南 一、技术背景与应用场景 随着微服务和海量并发请求的普及&#xff0c;Java应用在生产环境中对低延迟和高吞吐的需求日益显著。传统的CMS和Parallel GC 在大内存场景下常出现Full GC 停顿时间长、吞吐下降等问题…

【JobScheduler】Android 后台任务调度的核心组件指南

JobScheduler 是 Android 平台上原生支持在直接启动模式&#xff08;Direct Boot Mode&#xff09;下执行任务的调度器。 相比 WorkManager 需要复杂的配置才能勉强支持直接启动&#xff0c;JobScheduler 在这方面有着天生的优势和明确的 API 支持。如果你面临的硬性要求是必须…

c# 调用basler 相机

目录 一联合halcon&#xff1a; 二 c# 原生 一联合halcon&#xff1a; 环境配置 下载安装pylon软件 下载安装halcon 创建 winform项目 test_basler 添加引用 打开pylon可以连接相机 可以看到我的相机id为23970642 &#xff08; c#联合halcon的基础教程&#xff08;案例…

《2025年AI产业发展十大趋势报告》四十六

《2025年AI产业发展十大趋势报告》四十六随着科技的迅猛发展&#xff0c;人工智能&#xff08;AI&#xff09;作为引领新一轮科技革命和产业变革的战略性技术&#xff0c;正逐步渗透到各个行业和领域&#xff0c;成为推动经济社会发展的重要引擎。2023年&#xff0c;生成式AI的…

c++ 杂记

1. 为什么返回*this?2. 3. 友元函数的使用&#xff1a;需要头文件中类内外声明&#xff0c;cpp文件中实现定义哦// Sales_data.h #ifndef SALES_DATA_H #define SALES_DATA_H#include <string>class Sales_data {std::string bookNo;int units_sold 0;double revenue …

PDF文件基础-计算机字体

计算机字体的原理包含了字符编码、字形渲染和字体文件存储三个关键技术。 字符编码负责将每个字符映射到一个唯一的数字码&#xff1b;字形渲染则将这些数字码转换成屏幕或纸张上可识别的图形&#xff1b;字体文件存储则包含了字符的编码、图形描述信息以及字体的其他属性&…

华为IP(9)

OSPF的基本配置OSPF路由计算前言&#xff1a;1)同一区域内的OSPF路由器拥有完全一致的LSDB&#xff0c;在区域内部&#xff0c;OSPF采用SPF算法完成路由计算。2&#xff09;随着网络规模不断扩大&#xff0c;路由器为了完成路由计算所消耗的内存、CPU资源也越来越多。通过区域划…

java.nio.file.InvalidPathException异常

一.问题概述 本人在ubuntu22.04的操作系统上&#xff0c;运行java程序时创建一个文件时&#xff0c;由于文件名称中包含了中文&#xff0c;所以导致了程序抛出了java.nio.file.InvalidPathException的异常。 java.nio.file.InvalidPathException: Malformed input or input co…

Next系统总结学习(一)

下面我按题号逐条 详细 解释并给出示例与最佳实践。为便于阅读&#xff0c;我会同时给出关键代码片段&#xff08;伪代码/实用例子&#xff09;&#xff0c;并指出常见坑与解决方案。 1. 你是如何理解服务端渲染&#xff08;SSR&#xff09;的&#xff1f;它的核心工作流程是怎…

房屋安全鉴定需要什么条件

房屋安全鉴定需要什么条件&#xff1a;专业流程与必备要素解析房屋安全鉴定是保障建筑使用安全的重要环节&#xff0c;它通过对建筑结构、材料性能及使用状况的全面评估&#xff0c;为房屋的安全使用、改造或维护提供科学依据。随着城市建筑老化及自然灾害频发&#xff0c;房屋…

现代C++:现代C++?

C语言正在走向完美&#xff0c;所以&#xff0c;C语言值得学习&#xff08;甚至研究&#xff09;&#xff0c;这些知识可以成为一切编程的基础。然而在实践中&#xff0c;不必全面的使用C语言的各种特性&#xff0c;而应根据工程项目的实际情况&#xff0c;适当取舍&#xff08…

【C++】哈希表实现

1. 哈希概念 哈希(hash)又称散列&#xff0c;是⼀种组织数据的方式。从译名来看&#xff0c;有散乱排列的意思。本质就是通过哈希 函数把关键字Key跟存储位置建立一个映射关系&#xff0c;查找时通过这个哈希函数计算出Key存储的位置&#xff0c;进行快速查找 1.1 直接定址法…

ai 玩游戏 llm玩街霸 大模型玩街霸 (3)

1. 开源代码地址&#xff1a; https://github.com/OpenGenerativeAI/llm-colosseum 2. 架构&#xff1a; 3. 图片&#xff1a; 4. 感觉还是下面的步骤&#xff1a; a. 实时理解游戏当前环境&#xff0c;英雄角色&#xff0c;英雄状态 b. 根据当前状态感知&#xff0c;生成英雄…

2025年渗透测试面试题总结-59(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 一、SQL注入全解 二、XSS与文件漏洞 三、服务端漏洞专题 四、职业经验与能力评估 1、注入攻击原理是什么…

GPT系列--类GPT2源码剖析

无需多言&#xff0c;大家应该都用过了&#xff0c;如今都更新到GPT-5了。1. GPT-1回到2018年的NLP&#xff0c;神仙打架&#xff0c;BERT与GPT不分先后。GPT是“Generative Pre-Training”的简称&#xff0c;生成式的预训练。BERT和GPT肯定是GPT难训练&#xff0c;引用量也是B…

这是一款没有任何限制的免费远程手机控制手机的软件

这是一款没有任何限制的免费远程手机控制手机的软件支持安卓和苹果1.安装1.1被控制端安装airdroid1.2控制端air mirror2.登录账号控制端和被控制端登录同一个账号3.控制打开控制端软件选择要控制的机器直接点“远程控制“

Observability:更智能的告警来了:更快的分诊、更清晰的分组和可操作的指导

作者&#xff1a;来自 Elastic Drew Post 探索 Elastic Stack 告警的最新增强功能&#xff0c;包括改进的相关告警分组、将仪表盘链接到告警规则&#xff0c;以及将调查指南嵌入到告警中。 在 9.1 版本中&#xff0c;我们对告警进行了重大升级&#xff0c;帮助 SRE 和运维人员更…

数智之光燃盛景 共同富裕创丰饶

8月29日&#xff0c;2025数博会“一带一路”国际大数据产业发展暨数智赋能新时代、共同富裕向未来的会议在贵阳国际生态会议中心隆重举行。作为全球大数据领域的重要盛会&#xff0c;此次活动吸引了来自联合国机构、国际组织、科研院所、知名企业等社会各界的百余位代表&#x…