多态及相关

多态及相关

  • 多态的概念
  • 多态实现的两个条件及特殊情况
    • 虚函数
    • 虚函数重写的例外
    • C++11 override 和 final
  • 重载、覆盖(重写)、隐藏(重定义)的对比
  • 题目1
  • 抽象类
    • 接口继承和实现继承
  • 题目2(很重要)
  • 多态的原理
    • 虚函数表
      • 为什么Derive中的func4()在监视窗口里没有显示出来?
      • 虚函数和虚表都存在于哪里?
    • 静态绑定和动态绑定
  • 区分虚函数表和虚基类表
  • 单继承和多继承关系的虚函数表
  • 菱形继承和菱形虚拟继承(了解)
    • 菱形继承
    • 菱形虚拟继承
  • 题目3

多态的概念

多态:在C++中,多态就是不同的对象去实现同一个函数可以实现出不同的效果。多态是建立在继承的基础上的。
接着举一些生活中的例子: 例如,学生和普通人买火车高铁票,同样是去买票,学生可以享受到学生票价。 又比如,支付宝中对于新用户和老用户抢红包的奖励也是不一样的,通常新用户的红包会更大。 这些都是多态的表现。

多态实现的两个条件及特殊情况

多态是建立在继承的概念上的,多态还需要满足两个条件才能实现。
①必须通过基类的指针或者引用调用虚函数
②被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

虚函数

虚函数:即被virtual修饰的类成员函数称为虚函数。

class Person 
{public:virtual void BuyTicket() { cout << "买票-全价" << endl;}
};

虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。
这里强调一个点: 重写是对函数的内容进行修改,既然保持函数的返回值类型、函数名字、参数类型完全相同,那么我们重写的不就是函数的内容吗。
重写还有一些概念,我会放在下面再次提到。

class Person 
{public:virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person 
{public:virtual void BuyTicket() { cout << "买票-半价" << endl; }  //构成重写
}

在这里插入图片描述

虚函数重写的例外

①协变(基类与派生类虚函数返回值类型不同)
派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指
针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。

class Person 
{
public:virtual Person* BuyTicket()   //基类虚函数返回基类的指针或引用{ cout << "买票-全价" << endl;return nullptr;}
};
class Student : public Person
{
public:virtual Student* BuyTicket()  //派生类虚函数返回派生类的指针或引用{cout << "买票-半价" << endl;return nullptr;}void Func(Person& p){p.BuyTicket();}
};

②析构函数的重写(基类与派生类析构函数的名字不同)
我们先前在模拟写析构函数的时候,都是写 ~类名()的形式 。但是我们多态调用析构函数时,如果写成同函数名的话,是不是很反常。 所以在C++有个规定,编译器会对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor。 所以我们可以对析构函数进行特殊处理,基类与派生类析构函数的名字可以不同

结果符合预期,先调用Person的析构。 后面对派生类析构的时候,再自动对Person进行一次析构。
在这里插入图片描述

但如果,我们不对派生类进行重写会发生什么呢?
在这里插入图片描述
③如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写

class Person {
public:virtual ~Person() { cout << "~Person()" << endl; }
};
class Student : public Person {
public:~Student() { cout << "~Student()" << endl; }  //省略virtual关键字
};

此时,依然构成重写。但是基类的virtual不可以省略。并且也不推崇这个写法,建议还是加上。

C++11 override 和 final

从上面可以看出,C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的。因此:C++11提供了override和final两个关键字,可以帮助用户检测是否重写。

override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。
给派生类加了override关键字,基类成员函数没加virtual,不构成重写,报错。
在这里插入图片描述
final:修饰虚函数,表示该虚函数不能再被重写
给基类虚函数加了final,该虚函数就不能再被重写,派生类因重写报错了。(不加就不会报错)
在这里插入图片描述

重载、覆盖(重写)、隐藏(重定义)的对比

重载:重载是之前学的,函数重载的条件是函数必须在同一个作用域内,并且函数的函数名得相同参数名不同,这样构成函数重载。
重写/覆盖: 重写上面有提到,要求重写的函数在不同的作用域内,分别在基类和派生类中,函数必须是虚函数才行,并且重写的函数需满足函数名,参数(缺省函数和非缺省函数都得一致,缺省值可以不相同),返回值都相等!!(协变除外)。
重定义/隐藏: 重定义和重写属于一个互斥的关系,满足其一就不可能再符合另一种。 重定义同样要求重定义的函数分别在基类和派生类中,但对于函数的条件有所不同。首先,不要求为虚函数了,只要求函数的函数名相同就可以了。 强调,重写和重定义是互斥的!!

我们怎么分清重写和重定义的区别呢? 我的建议是,先看这两个函数能不能满足重写的条件(两个作用域,虚函数,函数名、参数、返回值都相等),如果不满足重写,但符合两个作用域且函数名相同的条件,那就叫重定义。

重写有一个点,我们在这里先铺垫一下: 函数重写,我们是对函数的定义,也就是内容进行修改。

题目1

class A
{
public:virtual void func(int val = 1){cout << val << endl;}
};
class B
{
public:virtual void func(int val = 2){cout << val << endl;}
};
int main()
{B b;b.func();A a;a.func();return 0;
}

此时,符合函数重写的条件。 打印的结果符合预期
在这里插入图片描述
假如我做一下修改

class A
{
public:virtual void func(int val = 1){cout << val << endl;}
};
class B
{
public:virtual void func(int val){cout << val << endl;}
};
int main()
{B b;b.func();A a;a.func();return 0;
}

此时,我们可以看到A中的函数有缺省值,而B中的函数没有,此时已经不符合函数重写的条件了,此时属于函数重定义的情况,也就是隐藏的情况。
在这里,调用B中的func(),如果不传参数,就会报错。 因为B中重定义了A中的函数,也就是B隐藏了A函数,那么再调用函数时,会去调用B的这个函数,而不会去寻找A中的这个函数了。又由于函数参数不匹配,就造成了编译不通过的问题。

抽象类

在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口
类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象 。 纯虚函数规范了派生类必须重写。
在这里插入图片描述
此时可以看到父类是不能被实例化对象的。如果我们不对派生类进行重写函数,那派生类也会不能实例化对象,看下面!
在这里插入图片描述

那么我们出抽象类的意义是什么呢? 不仅仅是为了让我们对派生类中的虚函数进行重写,还有一个点就是比方说这里Car是个大类,通常有这种情况,父类是个大类,里面包含一些大的属性让派生类继承就可以,并不一定要父类来实现某些函数,这些函数会抛给子类去实现,因此也不用对父类进行实例化,而子类想要实例化就必须对函数进行重写!

接口继承和实现继承

实现继承: 普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。(把函数实现的部分给一起继承下来了)
接口继承: 虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。(重写,是对函数的实现进行重写,继承下来的是虚函数的声明(函数名,参数,返回值等等))
所以如果不实现多态,不要把函数定义成虚函数,因为实现多态也是要付出相应代价的。

题目2(很重要)

下面代码输出的结果是什么?

class A
{
public:virtual void func(int val = 1) { std::cout << "A->" << val << std::endl; }virtual void test() { func(); }
};
class B : public A
{
public:void func(int val = 0) { std::cout << "B->" << val << std::endl; }
};
int main(int argc, char* argv[])
{B* p = new B;p->test();return 0;
}

我还要对这个题再进一步描述一下为什么这里this既然是A*了,在test中调用func为什么不是直接用A中的func打印出A->1,而是用A的声明,B的定义去打印出结果B->1
这里只需要理解两个点,就知道是为什么了?
①派生类重写虚函数,是对虚函数的定义进行重写,声明不会进行改变
②派生类传给父类,实际是对派生类中的父类部分进行了切割

画个简图方便大家理解一下::

下面再看一道题,和这个也是一样的。 我们再来验证一下:

class A
{
public:virtual void func(int val = 1){cout << val << endl;}
};
class B :public A
{
public:virtual void func(int val = 2){cout << val << endl;}
};
int main()
{A a;a.func();B b1;A(b1).func();B b2;b2.func();return 0;
}

结果:在这里插入图片描述
我们会发现我们将B类的b1,转换为A类型,那么去调用func用的就是,A的声明val=1去实现的。 当然,不要忘记,如果直接用B类的b2去调用func,那么this指针本身就是B*,那么会直接用B类中func的声明和定义打印出val=2。
指向谁就调用谁。 b1指向B类,即使转换成A类型,调用了A的虚函数声明,但最后还是会去B中重写的虚函数定义。 b2指向B类,没有转换,直接就使用B中虚函数的声明和定义。

多态的原理

虚函数表

定义:一个含有虚函数的类中都至少都有一个虚函数表指针,因为虚函数的地址要被放到虚函数表中,虚函数表也简称虚表。

首先,通过一个例子来引出

// 题目是求sizeof(Base)
class Base
{
public:
virtual void Func1()
{
cout << "Func1()" << endl;
}
private:
int _b = 1;
};

32位机器下,结果是8。
与之前的观念不同了,以前会认为只有一个int类型的_b,所以sizeof(Base)的大小是4,但是不然。 Base对象中出了int _b,还有一个虚函数表!
在这里插入图片描述
我们可以看到,b中比预期多了一个_vfptr。 这个就叫做虚函数表指针,v和f代表的是virtual fuction。 这个指针有什么用呢? 接着往下看:

class Base
{
public:virtual void Func1(){cout << "Base::Func1()" << endl;}virtual void Func2(){cout << "Base::Func2()" << endl;}void Func3(){cout << "Base::Func3()" << endl;}
private:int _b = 1;
};
class Derive : public Base
{
public:virtual void Func1(){cout << "Derive::Func1()" << endl;}
private:int _d = 2;
};
int main()
{Base b;Derive d;return 0;
}

我们根据这个代码,还有接下来的监视,内存图看一些现象:
在这里插入图片描述
①Base中的func3由于不是虚函数,因此没有进入到虚函数表中去!
②b,d对象内存中第一行存放的是虚函数表的指针,通过这个指针可以找到虚函数表。
至于第二行存的是什么,我们下面也会讲到,第二行存的是虚基类表指针。
③d是b的派生类,我们可以观察到d中存放b的形式,可以看到与之前的继承很相似,但这次多出来一个虚函数表指针。派生类对象d中也有一个虚表指针,d对象由两部分构成,一部分是父类继承下来的成员,虚表指针存在部分的有一部分是自己的成员。
④基类b对象和派生类d对象虚表是不一样的,这里我们发现Func1完成了重写,所以d的虚表
中存的是重写的Derive::Func1,所以虚函数的重写也叫作覆盖,覆盖就是指虚表中虚函数
的覆盖。重写是语法的叫法,覆盖是原理层的叫法。

总结一下派生类的虚表生成:a.先将基类中的虚表内容拷贝一份到派生类虚表中 b.如果派生
类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函数 c.派生类自己
新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后。

那这里就产生了一个问题? 既然派生类自己新增加的虚函数会放到派生类虚表的最后,那么

为什么Derive中的func4()在监视窗口里没有显示出来?

实际上,确实监视窗口不会显示出来,那让我们来观察一下Derive中的_vfptr内存,看看是怎么一回事?
在这里插入图片描述
那么为了验证这个是否为func4,验证出我们上面写的结论,接下来进行详细验证:

typedef void(*VFPTR)();   //这就是函数指针的typedef的方法void PrintVFT(VFPTR* vft)  //写出一个print函数,来打印对应的函数地址,并且运行出来。这样就可以直观的看到结果
{for (size_t i = 0; i < 3; i++){printf("%p->", vft[i]);  //打印地址VFPTR pf = vft[i];(*pf)();   //执行这个函数  这个看起来奇怪,但函数指针就是这么用的}
}
int main()
{Base b;Derive d;// 首先我们的目的是为了取到_vfptr这个函数指针数组的地址,然后通过解引用下标的方式,//来访问到数组中的函数指针,从而打印函数地址并实现函数//VFPTR* ptr = &d;   // 此时编译时不通过的,因为 &d是Derive*,不能强转成VFPTR*// 所以为了强转成功,我们得借助int来实现VFPTR* ptr = (VFPTR*)(*((int*)&d));  PrintVFT(ptr);return 0;
}

在PrintVFT函数中,通过打印地址,执行函数的方式,我们就可以得到结论,fun4是存在于派生类虚表中的,只是在监视窗口中显示不出来(可以理解成是bug)

再思考一个问题?

虚函数和虚表都存在于哪里?

虚函数存在虚表中。虚表存的是虚函数指针,不是虚函数,虚函数和普通函数一样的,都是存在代码段的(验证过程省略了) 虚表也同样存在于代码段!!=

静态绑定和动态绑定

静态绑定又称为前期绑定(早绑定),在程序编译期间确定了程序的行为,也称为静态多态,比如:函数重载
动态绑定又称后期绑定(晚绑定),是在程序运行期间,根据具体拿到的类型确定程序的具体行为,调用具体的函数,也称为动态多态。

区分虚函数表和虚基类表

虚函数表属于一个函数指针数组,里面存放的函数指针可以找到对应的虚函数
虚基类表我们在继承那里提到过,它是在派生类继承父类时,多加一个virtual关键字,使得成为虚基类,此时就会有一个虚基类表的指针存放在派生类所继承的父类里的内存中,指针指向的虚基类表中有一个参数会显示当前位置距离父类的偏移量

单继承和多继承关系的虚函数表

单继承的虚函数表相信通过上面的描述,已经非常清楚了。这里再进行总结一下
继承过来的虚函数表做两件事: 更新虚函数表指针,以及虚函数如果有重新,就更新对应虚函数的定义
在这里插入图片描述

多继承:

class Base1 {
public:virtual void func1() { cout << "Base1::func1" << endl; }virtual void func2() { cout << "Base1::func2" << endl; }
private:int b1;
};
class Base2 {
public:virtual void func1() { cout << "Base2::func1" << endl; }virtual void func2() { cout << "Base2::func2" << endl; }
private:int b2;
};
class Derive : public Base1, public Base2 {
public:virtual void func1() { cout << "Derive::func1" << endl; }virtual void func3() { cout << "Derive::func3" << endl; }
private:int d1;
};

多继承呢相比单继承,一样该做那两件事。 但是呢,形式上肯定会有略微的不同。
在这里插入图片描述

菱形继承和菱形虚拟继承(了解)

菱形继承

class A
{
public:virtual void func1() { cout << "A::func1" << endl; }int _a;
};
class B : public A
{
public:virtual void func2() { cout << "B::func2" << endl; }int _b;
};
class C : public A
{
public:virtual void func3() { cout << "C::func3" << endl; }int _c;
};
class D : public B, public C
{
public:virtual void func4() { cout << "D::func4" << endl; }int _d;
};int main()
{D d;cout << sizeof(d) << endl;   // 结论菱形继承的对象模型跟多继承类似d.B::_a = 1;d.C::_a = 2;d._b = 3;d._c = 4;d._d = 5;return 0;
}

打印出来的结果会是多少呢?在这里插入图片描述
为什么?怎么来的? 分析一下:
在这里插入图片描述

菱形虚拟继承

class A
{
public:virtual void func1() { cout << "A::func1" << endl; }int _a;
};
//class B : public A
class B : virtual public A
{
public:virtual void func2() { cout << "B::func2" << endl; }int _b;
};
//class C : public A
class C :virtual public A
{
public:virtual void func3() { cout << "C::func3" << endl; }int _c;
};
class D : public B, public C
{
public:virtual void func4() { cout << "D::func4" << endl; }int _d;
};int main()
{D d;cout << sizeof(d) << endl;// 结论菱形继承的对象模型跟多继承类似d.B::_a = 1;d.C::_a = 2;d._b = 3;d._c = 4;d._d = 5;return 0;
}

这次的结果是:在这里插入图片描述
同样的我们来分析一下:
此时虚基类A是共享的,内存中的形式就发生了变化!
在这里插入图片描述

题目3

请问输出结果为多少?

class A
{
public:A ():m_iVal(0){test();}virtual void func() { std::cout<<m_iVal<<‘ ’;}void test(){func();}
public:int m_iVal;
};
class B : public A
{
public:B(){test();}virtual void func(){++m_iVal;std::cout<<m_iVal<<‘ ’;}
};
int main(int argc ,char* argv[])
{A*p = new B;p->test();return 0;
}

结果: 0 1 2
思路:首先调用的是A的构造函数,此时,B还没有构造出来,因此不构成多态,直接调用A中的func(),打印出0。因为B继承了A(如果是多继承,先继承的先初始化)接着后面才构造B,此时就已经构成多态了,所以B中的A切割过去了,此时使用A的声明,B的定义完成func(),val++,打印出1。 后面通过p调用test(),同理,使用A的声明,B的定义完成func(),val++,打印出2。

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

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

相关文章

利用大模型提升个性化推荐的异构知识融合方法

在推荐系统中&#xff0c;分析和挖掘用户行为是至关重要的&#xff0c;尤其是在美团外卖这样的平台上&#xff0c;用户行为表现出多样性&#xff0c;包括不同的行为主体&#xff08;如商家和产品&#xff09;、内容&#xff08;如曝光、点击和订单&#xff09;和场景&#xff0…

Javascript基础(三)

Javascript基础&#xff08;一&#xff09; Javascript基础&#xff08;二&#xff09; 引用数据类型 在之前的文章中&#xff0c;我们提及了与基本数据类型并列的引用数据类型&#xff0c;当时提到引用数据类型大致分为三类&#xff1a;数组Array&#xff0c;函数Function&a…

GPT-ArcGIS数据处理、空间分析、可视化及多案例综合应用

在数字化和智能化的浪潮中&#xff0c;GIS&#xff08;地理信息系统&#xff09;和GPT&#xff08;生成式预训练模型&#xff09;的结合正日益成为推动科研、城市规划、环境监测等领域发展的关键技术。GIS以其强大的空间数据处理、先进的空间分析工具、灵活的地图制作与可视化能…

JavaEE初阶-多线程易忘点总结

文章目录 1.PCBPID文件描述符表内存指针状态上下文优先级记账信息tgid 2.线程与进程的区别3.sleep和interrupt方法的关系变量终止线程interrupt方法终止线程 4.线程状态5.出现线程不安全的原因线程在系统中是随即调度&#xff0c;抢占式执行的。多个线程修改同一个变量线程针对…

《MySQL对数据库中表的结构的操作》

文章目录 一、建表二、查看表结构所有能查看到数据库&#xff0c;表的操作痕迹的本质都是服务器保存下来了这些操作记录。 三、修改表1.改表名字2.添加表记录3.添加表的更多字段4.修改表的字段5. 删除表的字段 总结 以下的数据库表的操作全是基于user_db这个数据库操作的&#…

如何加入亚马逊云科技AWS特邀技领云合作博主

这一年来&#xff0c;小李哥帮助过上千名小伙伴学习AWS和考取认证&#xff0c;这次非常荣幸能和丸子爸比大哥、程序员学习日常成为第一批亚马逊AWS云领袖计划的特邀合作博主&#xff01;感谢AWS培训与认证各位老师的支持&#xff0c;未来小李哥会继续坚持社区分享&#xff0c;带…

AC自动机

AC自动机 AC自动机有一个很出色的功能&#xff1a;实现多模式匹配。 多模式匹配&#xff1a;模式串有多个&#xff0c;主串只有一个&#xff0c;要进行多次模式串匹配。如果用KMP就要一个一个模式串进行匹配&#xff0c;效率低。AC自动机就可以做到&#xff0c;只要经过一些预…

【全网首出】npm run serve报错 Expression: thread_id_key != 0x7777

总结 困扰了一天&#xff01;&#xff01;&#xff01;一直以为是自己哪里配置错了&#xff0c; 结果最后发现是node.js官方的问题&#xff0c; Node.js v16.x版本的fibers.node被弃用 本文阅读大概&#xff1a;3min #npm run serve时就报错 #找了一天的文章&#xff0c;找不…

# 从浅入深 学习 SpringCloud 微服务架构(八)Sentinel(1)

从浅入深 学习 SpringCloud 微服务架构&#xff08;八&#xff09;Sentinel&#xff08;1&#xff09; 一、sentinel&#xff1a;概述 1、前言 – 服务熔断 Hystrix 的替换方案。 1&#xff09;2018年底 Netflix 官方宣布 Hystrix 已经足够稳定&#xff0c;不再积极开发 Hys…

JVM笔记2--垃圾收集算法

1、如何确认哪些对象“已死” 在上一篇文章中介绍到Java内存运行时的各个区域。其中程序计数器、虚拟机栈、本地方法栈3个区域随着线程而生&#xff0c;随线程而灭&#xff0c;栈中的栈帧随着方法的进入和退出而有条不紊的执行着入栈和出栈操作。每个栈帧中分配多少内存基本上…

组队竞赛和删除公共字符

这里附上两个题目的链接 题目一&#xff1a;删除公共字符_牛客题霸_牛客网 (nowcoder.com) 题目二&#xff1a;组队竞赛_牛客笔试题_牛客网 (nowcoder.com) 第一题 分析&#xff1a; 当我们看见这个题目的时候&#xff0c;可以使用传统的暴力查找方式&#xff0c;如判断第一个…

VsCode | 修改首页启动页 Logo

VsCode | 修改首页启动页 Logo 最终效果&#xff1a; 插件的安装 先安装插件 Custom CSS and JS Loader 插件配置 Ctrl Shift P 输入 打开用户设置&#xff0c;在末尾添加 "vscode_custom_css.imports": [""]下载 Logo 下载 Logo 点我下载 引入…

亚马逊云科技AWS免费证书-EC2服务器设计(含题库)

亚马逊云AWS官方程序员专属免费证书又来了&#xff01;这次证书是关于AWS EC2实例的设计和搭建&#xff0c;EC2作为AWS服务的核心&#xff0c;是学好AWS的第一步。强推没有任何AWS背景和转码的小伙伴去学&#xff01;学完也能变成AWS开发大神&#xff01; 证书名字叫Getting St…

使用 TensorFlow 和 Keras 构建 U-Net

原文地址&#xff1a;building-a-u-net-with-tensorflow-and-keras 2024 年 4 月 11 日 计算机视觉有几个子学科&#xff0c;图像分割就是其中之一。如果您要分割图像&#xff0c;则需要在像素级别决定图像中可见的内容&#xff08;执行分类时&#xff09;&#xff0c;或者从像…

Oracle23ai来了,23爱,全能、超级巨兽...

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验&#xff0c; Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主&#xff0c;全网粉丝10万 擅长主流Oracle、My…

[图解]关于SysML v2(1)大刀阔斧 对比 伪创新圈子

1 00:00:03,960 --> 00:00:08,270 OMG在2月份&#xff0c;这里写了4月 2 00:00:08,440 --> 00:00:13,530 应该是2月&#xff0c;发布了 3 00:00:13,870 --> 00:00:17,700 SysML v2的 beta 2版本 4 00:00:17,870 --> 00:00:19,780 也是当前最新的版本 5 00:00:2…

ES的脑裂现象

目录 0 集群结点的职责1 什么是脑裂现象2 造成脑裂现象的原因2.1 网络问题&#xff08;最常见&#xff09;2.2 主节点负载过大&#xff0c;资源耗尽&#xff0c;别的结点ping不到主节点2.3 主节点JVM内存回收时间过长导致 3 脑裂现象的解决方案3.1 局域网部署3.2 角色分离&…

python实验一 简单的递归应用

实验一 实验题目 1、兔子繁殖问题(Fibonacci’s Rabbits)。一对兔子从出生后第三个月开始&#xff0c;每月生一对小兔子。小兔子到第三个月又开始生下一代小兔子。假若兔子只生不死&#xff0c;一月份抱来一对刚出生的小兔子&#xff0c;问一年中每个月各有多少只兔子。 &…

[每日AI·0501]GitHub 版 Devin,Transformer的强力挑战者 Mamba,Sora 制作细节与踩坑,OpenAI 记忆功能

AI 资讯 国资委&#xff1a;加快人工智能等新技术与制造全过程、全要素深度融合GitHub版 Devin 上线&#xff0c;会打字就能开发应用&#xff0c;微软 CEO&#xff1a;重新定义 IDE在12个视频理解任务中&#xff0c;Mamba 先打败了 TransformerSora 会颠覆电影制作吗&#xff…

Oracle 23c? No Oracle 23ai

昨天 Oracle 发布了最新的Oracle版本。出乎意料的是这个版本从Oracle 23c 更名为 Oracle 23ai &#xff0c;似乎预示着Oracle的掌舵人Larry也要全面拥抱AI技术浪潮了。 23ai版本主要功能介绍: Oracle Database 23ai 是 Oracle 数据库的下一个长期支持版本。它包括 300 多项新功…