C++——多态
目录
前言
1. 多态的概念
2. 多态的定义及其实现
2.1 多态的构成条件
2.1.1 实现多态的两个重要条件
2.1.2 虚函数
2.1.3 虚函数的重写/覆盖
2.1.4 多态场景的⼀个选择题
2.1.5 虚函数重写的⼀些其他问题
2.1.5.1 协变(了解)
2.1.5.2 析构函数的重写
2.1.6 override和final关键字
2.1.7 重载/重写/隐藏的对比
3. 纯虚函数和抽象类
4. 多态的原理
4.1 虚函数表指针
4.2 多态的实现原理
4.3 动态绑定与静态绑定
4.4 虚函数表
5. 总结
前言
前面我们介绍了继承的相关内容,今天我们来介绍多态,这也是C++中一个非常重要的概念。在笔试和面试中经常会考到,所以大家如果对C++感兴趣,请继续阅读本篇内容,下面进入正文部分。
1. 多态的概念
多态(polymorphism)的概念:通俗来说,就是多种形态。
多态分为编译时多态(静态多态)和运行时多态(动态多态),这⾥我们重点讲运行时多态,编译时多态(静态多态)主要就是我们前⾯讲的函数重载和函数模板,他们传不同类型的参数就可以调用不同的函数,通过参数不同达到多种形态,之所以叫编译时多态,是因为他们实参传给形参的参数匹配是在编译时完成的,我们把编译时⼀般归为静态,运⾏时归为动态。 运行时多态,具体点就是去完成某个行为(函数),可以传不同的对象就会完成不同的行为,就达到多种形态。
比如买票这个行为,当普通人买票时,是全价买票;学⽣买票时,是优惠买票(5折或75折);军⼈买票时是优先买票。再比如,同样是动物叫的⼀个行为(函数),传猫对象过去,就是”喵“,传狗对象过去,就是"汪汪"。
2. 多态的定义及其实现
2.1 多态的构成条件
多态是⼀个继承关系的下的类对象,去调⽤同⼀函数,产生了不同的行为。比如Student继承了 Person。Person对象买票全价,Student对象优惠买票。
2.1.1 实现多态的两个重要条件
第⼀必须是基类的指针或引用,因为只有基类的指针或引用才能既指向基类对象又指向派生类对象;
第⼆派⽣类必须对基类的虚函数完成重写/覆盖,重写或者覆盖了,基类和派生类之间才能有不同的函数,多态的不同形态效果才能达到。
2.1.2 虚函数
类成员函数前面加virtual修饰,那么这个成员函数被称为虚函数。
注意:非成员函数不能加virtual修饰。
class Person
{
public:virtual void BuyTicket() { cout << "买票-全价" << endl;}
};
2.1.3 虚函数的重写/覆盖
虚函数的重写/覆盖:派生类中有⼀个跟基类完全相同的虚函数(即派⽣类虚函数与基类虚函数的返回值 类型、函数名字、参数列表完全相同),称派⽣类的虚函数重写了基类的虚函数。
#include<iostream>
using namespace std;
class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:virtual void BuyTicket() { cout << "买票-打折" << endl; }
};
void Func(Person* ptr)
{// 这里可以看到虽然都是Person指针Ptr在调⽤BuyTicket // 但是跟ptr没关系,⽽是由ptr指向的对象决定的。 ptr->BuyTicket();
}
int main()
{Person ps;Student st;Func(&ps);Func(&st);return 0;
}#include<iostream>
using namespace std;
class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:virtual void BuyTicket() { cout << "买票-打折" << endl; }
};
void Func(Person& ptr)
{// 这里可以看到虽然都是Person指针Ptr在调⽤BuyTicket // 但是跟ptr没关系,⽽是由ptr指向的对象决定的。 ptr.BuyTicket();
}
int main()
{Person ps;Student st;Func(ps);Func(st);return 0;
}
买票-全价
买票-打折
C:\code\test_c\test_2025_1_4\x64\Debug\test_2025_1_4.exe (进程 11008)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
这里大家会发现输出的对象是根据ptr指向的对象决定的,如果按照我们以前的思想,这里要调用两次Person中的函数;但是这里就是多态的特性,大家需要转变一下思维模式。
大家再来看下面代码,稍微改一下;
#include<iostream>
using namespace std;
class Person {
public:void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:virtual void BuyTicket() { cout << "买票-打折" << endl; }
};
void Func(Person* ptr)
{// 这里可以看到虽然都是Person指针Ptr在调⽤BuyTicket // 但是跟ptr没关系,⽽是由ptr指向的对象决定的。 ptr->BuyTicket();
}
int main()
{Person ps;Student st;Func(&ps);Func(&st);return 0;
}
我将基类中的virtual去掉了,代码的结果将会发生改变;
买票-全价
买票-全价
C:\code\test_c\test_2025_1_4\x64\Debug\test_2025_1_4.exe (进程 13476)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
大家发现结果变化了,只调用了Person中的函数,这里去掉vurtual就破坏了多态的要求,因此也就无法构成多态。
注意:在重写基类虚函数时,派⽣类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派⽣类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用,不过在考试选择题中,经常会故意出这个坑,让你判断是否构成多态。其实这里是构成多态的,大家可以这样来思考,子类继承父类,将virtual的属性也继承了下来。
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;}
};
void letsHear(const Animal& animal)
{animal.talk();
}
int main()
{Cat cat;Dog dog;letsHear(cat);letsHear(dog);return 0;
}
(>^ω^<)喵
汪汪
C:\code\test_c\test_2025_1_4\x64\Debug\test_2025_1_4.exe (进程 3264)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
2.1.4 多态场景的⼀个选择题
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;
}
本题首先上来要确定一个点,那就是调A中的test函数时,这里面的this指针的类型到底是A*还是B*呢?相信大家有不同的看法,但是这里答案是A*,因为B虽然是继承A,但是它并没有出现test函数,如果B有test函数,那么就会调B的,这样构成隐藏,继承并不会真的将A中的所有成员函数都弄到B中;
经过上面的分析,我们可以发现这里就构成多态了,那么此时指针指向B,那么就调用B中的func函数(this->func()),那么打印结果很多人这时就知道了,为“B->0”。
那么答案是D吗?咱们可以来验证一下;
B->1
C:\code\test_c\test_2025_1_4\x64\Debug\test_2025_1_4.exe (进程 13644)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
大家可以看到,运行结果是B选项;此时相信很多人都被坑到了,这到底是为什么呢?其实这涉及一个知识的理解,就是对于“重写” 的理解,大家需要知道,重写是重写函数的实现部分,也就是函数体,所以这里B中的func函数其实重写的函数体的内容,而val值其实还是A中的。所以本题的结果是“B->1”。
2.1.5 虚函数重写的⼀些其他问题
2.1.5.1 协变(了解)
派⽣类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派⽣类虚函数返回派⽣类对象的指针或者引用时,称为协变。协变的实际意义并不⼤,所以我们 了解⼀下即可。
class A {};
class B : public A {};
class Person {
public:virtual A* BuyTicket() { cout << "买票-全价" << endl;return nullptr;}
};
class Student : public Person {
public:virtual B* BuyTicket() { cout << "买票-打折" << endl;return nullptr;}
};
void Func(Person* ptr)
{ptr->BuyTicket();
}
int main()
{Person ps;Student st;Func(&ps);Func(&st);return 0;
}
2.1.5.2 析构函数的重写
基类的析构函数为虚函数,此时派⽣类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派⽣类析构函数名字不同看起来不符合重写的规则,实际上编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统⼀处理成destructor,所以基类的析构函数加了vialtual修饰,派⽣类的析构函数就构成重写。
下⾯的代码我们可以看到,如果~A(),不加virtual,那么deletep2时只调调的A的析构函数,没有调用B的析构函数,就会导致内存泄漏问题,因为~B()中在释放资源。
注意:这个问题⾯试中经常考察,⼤家⼀定要结合类似下⾯的样例才能讲清楚,为什么基类中的析构函数建议设计为虚函数。
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的析构函数,下⾯的delete对象调⽤析构函数,才能
构成多态,才能保证p1和p2指向的对象正确的调⽤析构函数。
int main()
{A* p1 = new A;A* p2 = new B;delete p1;delete p2;return 0;
}
2.1.6 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; }
};
int main()
{return 0;
}
error C3668: “Benz::Drive”: 包含重写说明符“override”的方法没有重写任何基类方法。
class Car
{
public:virtual void Drive() final {}
};
class Benz :public Car
{
public:virtual void Drive() { cout << "Benz-舒适" << endl; }
};
int main()
{return 0;
}
error C3248: "Car::Drive": 声明为 "final" 的函数不能由 "Benz::Drive" 重写。
2.1.7 重载/重写/隐藏的对比
3. 纯虚函数和抽象类
在虚函数的后⾯写上=0,则这个函数为纯虚函数,纯虚函数不需要定义实现(实现没啥意义因为要被派生类重写,但是语法上可以实现),只要声明即可。
包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象,如果派⽣类继承后不重写纯虚函数,那么派⽣类也是抽象类。纯虚函数某种程度上强制了 派⽣类重写虚函数,因为不重写实例化不出对象。
#include<iostream>
using namespace std;
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;}
};
int main()
{// 编译报错:error C2259: “Car”: ⽆法实例化抽象类 //Car car;Car* pBenz = new Benz;pBenz->Drive();Car* pBMW = new BMW;pBMW->Drive();return 0;
}
Benz-舒适
BMW-操控
C:\code\test_c\test_2025_1_5\x64\Debug\test_2025_1_5.exe (进程 6280)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
4. 多态的原理
4.1 虚函数表指针
关于多态的原理,这里由一道题来引入;
下⾯编译为32位程序的运行结果是什么()
A.编译报错
B.运行报错
C.8
D.12
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;
}
本题让我们来求这个类对象的大小,那么我们知道成员函数不是存在类里面的,打眼一看就两个成员变量,那么就8字节呗。
实际上问题并没有这么简单,大家先来看一下运行结果;
12
C:\code\test_c\test_2025_1_5\Debug\test_2025_1_5.exe (进程 13112)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
大家可以看到,上面是在X86环境下的运行结果,为12字节。那么为什么多出来4个字节呢?
其实除了_b和_ch成员,还多⼀个__vfptr放在对象的前面(注意有些平台可能会放到对象的最后⾯,这个跟平台有关),对象中的这个指针我们叫做虚函数表指针(v代表virtual,f代 表function)。⼀个含有虚函数的类中都至少都有⼀个虚函数表指针,因为⼀个类所有虚函数的地址要被放到这个类对象的虚函数表中,虚函数表也简称虚表,本质上它是一个函数指针数组。
class Base
{
public:virtual void Func1(){cout << "Func1()" << endl;}virtual void Func2(){cout << "Func2()" << endl;}void Func3(){cout << "Func3()" << endl;}
protected:int _b = 1;char _ch = 'x';
};
int main()
{Base b;cout << sizeof(b) << endl;return 0;
}
这里我多加了几个函数,大家在监视窗口可以发现,b中存了两个函数指针,而Func3没有存,因为前面没有加virtual。
4.2 多态的实现原理
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;
}
买票-全价
买票-打折
买票-优先
C:\code\test_c\test_2025_1_5\Debug\test_2025_1_5.exe (进程 4248)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
关于多态的原理,大家可以结合上面的图来进行理解,其实就一句话:指向谁调用谁,指向哪个对象,运行时,就到哪个对象的虚函数表中去找对应虚函数的地址,然后调用对应函数。
4.3 动态绑定与静态绑定
• 对不满⾜多态条件(指针或者引⽤+调⽤虚函数)的函数调⽤是在编译时绑定,也就是编译时确定调⽤ 函数的地址,叫做静态绑定。
• 满足多态条件的函数调用是在运行时绑定,也就是在运⾏时到指向对象的虚函数表中找到调⽤函数 的地址,也就做动态绑定。
// 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)
4.4 虚函数表
• 基类对象的虚函数表中存放基类所有虚函数的地址。同类型的对象共用同⼀张虚表,不同类型的象各自有独立的虚表,所以基类和派生类有各自独立的虚表。
• 派⽣类由两部分构成,继承下来的基类和自己的成员,⼀般情况下,继承下来的基类中有虚函数表 指针,⾃⼰就不会再⽣成虚函数表指针。但是要注意的这⾥继承下来的基类部分虚函数表指针和基类对象的虚函数表指针不是同⼀个,就像基类对象的成员和派⽣类对象中的基类对象成员也独立的。
• 派⽣类中重写的基类的虚函数,派⽣类的虚函数表中对应的虚函数就会被覆盖成派⽣类重写的虚函 数地址。
• 派⽣类的虚函数表中包含:(1)基类的虚函数地址,(2)派⽣类重写的虚函数地址完成覆盖,派⽣类 ⾃⼰的虚函数地址三个部分。
• 虚函数表本质是⼀个存虚函数指针的指针数组,⼀般情况这个数组最后⾯放了⼀个0x00000000
标记。(这个C++并没有进行规定,各个编译器自行定义的,vs系列编译器会再后⾯放个0x00000000 标记,g++系列编译不会放)
• 虚函数存在哪的?虚函数和普通函数⼀样的,编译好后是⼀段指令,都是存在代码段的,只是虚函数的地址又存到了虚表中。
• 虚函数表存在哪的?这个问题严格说并没有标准答案C++标准并没有规定,我们写下⾯的代码可以对比验证⼀下。vs下是存在代码段(常量区)。
5. 总结
本篇博客为大家介绍了C++中多态的内容,主要包括多态的语法、使用规则以及多态的原理;对于多态的原理,大家需要认真去理解,这也是C++(面向对象的语言)的特性,最后,希望本篇博客可以为大家带来帮助,感谢阅读!
相关文章:
C++——多态
目录 前言 1. 多态的概念 2. 多态的定义及其实现 2.1 多态的构成条件 2.1.1 实现多态的两个重要条件 2.1.2 虚函数 2.1.3 虚函数的重写/覆盖 2.1.4 多态场景的⼀个选择题 2.1.5 虚函数重写的⼀些其他问题 2.1.5.1 协变(了解) 2.1.5.2 析构函…...
什么是Transformer模型中的KV缓存:上下文新增那之前计算的KV还可用,在原有基础上对新增的进行计算就行
什么是Transformer模型中的KV缓存? 在Transformer模型中,KV缓存(Key-Value Cache)具有重要作用,以下是关于它的详细介绍: 概念含义 KV缓存主要是用于存储在模型推理过程中已经计算过的键(Key)和值(Value)信息。在Transformer架构里,比如在自注意力机制等计算环节…...
12.C语言中的struct详解:定义、赋值、指针、嵌套与位字段
目录 1.简介2.struct 的复制3.struct 指针4.struct 的嵌套5.位字段6.弹性数组成员 1.简介 本篇原文为:C语言中的struct详解:定义、赋值、指针、嵌套与位字段。 更多C进阶、rust、python、逆向等等教程,可点击此链接查看:酷程网 …...
洛谷 P3000 [USACO10DEC] Cow Calisthenics G
思路 题目要求断若干条边后形成的连通块中,最大的直径最小,很明显的二分。关键就在于如何写 c h e c k check check 函数了。 可以用 d f s dfs dfs 来判断要断哪条边。 一、 d [ u ] d[u] d[u] 定义 设 d [ u ] d[u] d[u] 为从 u u u 出发到子树…...
前端拿到zip中所有文件并下载为新的zip文件
问题原因:后端返回了一个zip格式文件供前端下载,然后下载后,形成了zip套zip的形式,当后端不愿处理时,前端不能坐以待毙 PS:当压缩包文件量过大,前端可能会出问题(脑测,未…...
JVM调优
jvm调优步骤:1发现问题、2。定位问题、3.解决问题 jdk自带的命令行调优工具: 1. jps 查看正在运行的 Java 进程 jps -v 查看进程启动时的JVM参数 options 参数: -q:仅仅显示 LVMID(local virtual machine id&#x…...
【前端】【HTML】入门基础知识
参考视频:【狂神说Java】HTML5完整教学通俗易懂_哔哩哔哩_bilibili 一、基本结构 二、基本标签 <h1>:一级标题,通常用于页面的主标题,字体较大且醒目。 <h2>:二级标题,用于副标题或主要章节标…...
Ubuntu桌面管理环境: GDM3,KDM,LightDM
介绍 Ubuntu是一个广受欢迎的Linux操作系统,拥有强大而多样化的桌面管理环境。其中三个常用的桌面管理环境是GDM3,KDM和LightDM。本篇博客将介绍这三个桌面管理环境的特点和功能。 GDM3 (GNOME Display Manager) GDM3是默认的桌面管理环境,…...
每天你好20250110(距离春节19天!!!)
亲爱的朋友们,大家早上好! 🌞 今晨乃 2025 年 1 月 10 日,星期五,农历乙巳[蛇]年十一月二十一日。祥蛇逸彩送祥,金乌喷薄耀世,晨晖破雾而来,恰似“赤日初升,其道大光”&…...
iOS 本地新项目上传git仓库,并使用sourceTree管理
此文记录的场景描述: iOS前期开发时,在本地创建项目,直至开发一段时间,初期编码及框架已完善后,才拿到git仓库的地址。此时需要将本地代码上传到git仓库。 上传至git仓库,可以使用终端,键入命令…...
计算机网络之---计算机网络的性能评估
计算机网络的性能评估是指通过各种标准和指标来衡量网络的工作效率和质量,进而对网络进行优化和改进的过程。评估的目标是确保网络能够满足预期的服务质量(QoS)和性能需求。常见的计算机网络性能评估指标包括带宽、延迟、吞吐量、丢包率等。 …...
对话|企业如何构建更完善的容器供应链安全防护体系
对话|企业如何构建更完善的容器供应链安全防护体系 云布道师 随着云计算和 DevOps 的兴起,容器技术和自动化成为软件开发中的必要手段,软件供应链也进入了自动化及 CI/CD 阶段。然而,容器技术和自动化虽然提升了软件的更新速度&…...
【SpringSecurity】二、自定义页面前后端分离
文章目录 1、用户认证流程AuthenticationSuccessHandler AuthenticationFailureHandlerSecurityFilterChain配置用户认证信息 2、会话并发处理2.1、实现处理器接口2.2、SecurityFilterChain配置 1、用户认证流程 AuthenticationSuccessHandler AuthenticationFailureHandler …...
在 Vue 3 集成 e签宝电子合同签署功能
实现 Vue 3 e签宝电子合同签署功能,需要使用 e签宝提供的实际 SDK 或 API。 e签宝通常提供针对不同平台(如 Web、Android、iOS)的 SDK,而 Web 端一般通过 WebView 或直接使用嵌入式 iframe 来加载合同签署页面。 下面举个 &…...
基于华为ENSP的OSPF接口网络类型深入浅出(4)
本篇技术博文摘要 🌟 OSPF的接口在不同网络类型下的工作方式;不同网络类型下的报文通告方式深入浅出hub-spoke架构 引言 📘 在这个快速发展的技术时代,与时俱进是每个IT人的必修课。我是肾透侧视攻城狮,一名什么都会一…...
西电-算法分析-研究生课程复习笔记
24年秋的应该是张老师最后一次用卷面考试,他说以后这节课的期末考试都是在OJ上刷题了张老师上课还挺有意思的,上完之后能学会独立地思考算法设计问题了。整节课都在强调规模压缩这个概念,考试也是考个人对这些的理解,还挺好玩的哈…...
音频数据增强:提升音频信号质量的多种技术
在音频处理和机器学习领域,音频数据增强是一种常用的技术,旨在通过对原始音频信号进行各种变换和处理,生成更多样化的训练数据。这不仅可以提高模型的鲁棒性,还能改善其在真实世界应用中的表现。本文将介绍几种常用的音频数据增强…...
如何在 Ubuntu 22.04 上安装 Caddy Web 服务器教程
简介 Caddy 是一个开源的 Web 服务器,它支持静态和现代 Web 应用程序,使用预定义的配置规则,并为所有链接的域名自动启用 HTTPS。Caddy 使用 GO 语言编写,提供了用户友好的配置指令,使你既可以将其用作 Web 服务器&am…...
python_excel列表单元格字符合并、填充、复制操作
读取指定sheet页,根据规则合并指定列,填充特定字符,删除多余的列,每行复制四次,最后写入新的文件中。 import pandas as pd""" 读取指定sheet页,根据规则合并指定列,填充特定字…...
基于GAN和RL的思想来训练对话生成
Paper https://arxiv.org/pdf/1701.06547.pdf 基于GAN和RL的思想来训练对话生成 Implementation https://github.com/jiweil/Neural-Dialogue-Generation/tree/master/Adversarial...
小米路由器IPv6 功能使用指南
本文不限于多层路由使用IPv6 的情况,提供解决IPv6 无法获取的更硬核的方法,需要有ssh 工具。(无安卓设备,测试环境win、mac、ios) 首先明确一点,就是如果想让你的设备得到GUA 地址,即访问 6.i…...
运放输入偏置电流详解
1 输入阻抗与输入偏置电路关系 在选择运放和仪表运放时,经常听到这样的说法:“需要非常高的输入阻抗”,事实上真实如此吗? 输入阻抗(更确切的说是输入电阻)很少会成为一个重要的问题(输入电容也…...
C++指针类型的基本理论和使用方式-学习记录
一、指针简概 (一)指针定义 指针(pointer)是“指向(point to)”另外一种类型的复合类型。与引用类似,指针也实现了对其他对象的间接访问。然而指针与引用相比又有很多不同点。其一,…...
Elasticsearch:使用 Playground 与你的 PDF 聊天
LLMs作者:来自 Elastic Toms Mura 了解如何将 PDF 文件上传到 Kibana 并使用 Elastic Playground 与它们交互。本博客展示了在 Playground 中与 PDF 聊天的实用示例。 Elasticsearch 8.16 具有一项新功能,可让你将 PDF 文件直接上传到 Kibana 并使用 Pla…...
计算机网络之---物理层设备
什么是物理层设备 物理层设备是指负责数据在物理媒介上传输的硬件设备,它们主要处理数据的转换、信号的传输与接收,而不涉及数据的内容或意义。常见的物理层设备包括网卡、集线器、光纤收发器、调制解调器等。 物理层设备有哪些 1、网卡(N…...
【Duilib】 List控件支持多选和获取选择的多条数据
问题 使用Duilib库写的一个UI页面用到了List控件,功能变动想支持选择多行数据。 分析 1、List控件本身支持使用SetMultiSelect接口设置是否多选: void SetMultiSelect(bool bMultiSel);2、List控件本身支持使用GetNextSelItem接口获取选中的下一个索引…...
2025新春烟花代码(二)HTML5实现孔明灯和烟花效果
效果展示 源代码 <!DOCTYPE html> <html lang"en"> <script>var _hmt _hmt || [];(function () {var hm document.createElement("script");hm.src "https://hm.baidu.com/hm.js?45f95f1bfde85c7777c3d1157e8c2d34";var …...
如何在 Ubuntu 22.04 上集成 Collabora Online 教程
简介 在本教程中,我们将详细讲解如何在 Ubuntu 22.04 操作系统上安装 Collabora Online。 Collabora Online 是一个基于 LibreOffice 技术的开源办公套件。它提供了许多功能,其中最有用的一个功能是 Collabora 提供了 Word 文档、电子表格、演示文稿等…...
Linux系统启动jar包--Java8
启动命令及参数 1. 启动命令模板 nohup java \ -Xms512m \ -Xmx1024m \ -Xmn256m \ -XX:MetaspaceSize128m \ -XX:MaxMetaspaceSize256m \ -XX:UseG1GC \ -XX:InitiatingHeapOccupancyPercent45 \ -XX:PrintGCDetails \ -XX:PrintGCDateStamps \ -XX:PrintGCApplicationStopp…...
linux-定制化rpm(rpmbuild)
一. 引文: 为实现我们的快速安装,特定服务需求的服务部署需求, 我们选择了通过source编译后定制成rpm,存放至自定义yum仓库,通过yum工具规范化管理及部署服务。目前比较常用的rpm打包方式分别为rpmbuild和fpm(在rpmbui…...
面向对象分析与设计Python版 分析与设计概述
文章目录 一、软件工程概述二、分析与设计概述 一、软件工程概述 高质量软件系统的基本要求 架构性内聚可重用性可维护性可扩展性灵活性 软件开发过程模型:是指根据软件开发项目从开始到结束的一系列步骤和方法,建模为不同的模型。常见的有࿱…...
npm发布流程说明
一、进入要发布的项目根目录,初始化为npm包 npm initname:最重要的字段之一,项目名称(少于214个字节)。没有name和version不能进行安装; version:最重要的字段之一,项目版本。没有n…...
Nginx反向代理请求头有下划线_导致丢失问题处理
后端发来消息说前端已经发了但是后端没收到请求。 发现是下划线的都没收到,搜索之后发现nginx默认request的header中包含’_’时,会自动忽略掉。 解决方法是:在nginx里的nginx.conf配置文件中的http部分中添加如下配置: unders…...
计网C1C2C3答案自用
Chapter 1 Computer Network and the Internet Review Questions Solution R1. What is the difference between a host and end system? List several different types of end system. Is a Web server an end system? There is no difference between a host and an end …...
为什么要分为大端和小端
1.大端序 0x12345678 地址: 0x00 0x01 0x02 0x03 数据: 0x12 0x34 0x56 0x78 高位字节存储在低地址,常用语网络协议,便于人阅读、书写类似。 2.小端序 0x12345678 地址: 0x00 0x01 0x02 0x03 …...
通过可穿戴外骨骼,以更灵活的方式操作你的机器人。
今天,我们将介绍一款专为控制 Mercury X1 和 Mercury B1 机械臂而设计的创新外骨骼。这种外骨骼以人类手臂的结构为蓝本,可实现直观和精确的控制。 开发这种外骨骼的动机源于人们对深度学习和机器学习等领域日益增长的兴趣。这些技术使机器人能够自主学习…...
【大数据基础】大数据概述
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈大数据技术原理与应用 ⌋ ⌋ ⌋专栏系统介绍大数据的相关知识,分为大数据基础篇、大数据存储与管理篇、大数据处理与分析篇、大数据应用篇。内容包含大数据概述、大数据处理架构Hadoop、分布式文件系统HDFS、分布式数…...
使用双向链表优化数组操作的性能
🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 背景 双向链表的优势 实现方案 性能优化 …...
Lua语言的语法
Lua语言的探索与应用 引言 Lua是一种轻量级、高性能的脚本语言,广泛应用于游戏开发、嵌入式系统和很多应用程序中。它的灵活性和高效性使得Lua成为软件开发中不可或缺的一部分。本文将从Lua的历史、语法、特色、使用案例及其在实际开发中的应用进行深入探讨。 Lu…...
Linux随记(十四)
一、处理vsftpd漏洞 【vsftpd安全漏洞(CVE-2021-30047)】 #操作系统1:bclinux euler 21.10#操作系统2:kylin v10二、处理ntp漏洞 【NTPMode6检测漏洞【原理扫描】】 #操作系统1:bclinux euler 21.10 cp /etc/ntp.conf /etc/ntp.conf.bak202…...
【Linux网络编程】第二十二弹---深入理解 I/O 多路转接之 epoll:系统调用、工作原理、代码演示及应用场景
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【Linux网络编程】 目录 1、I/O 多路转接之 epoll 1.1、epoll 初识 1.2、epoll 的相关系统调用 1.2.1、epoll_create 1.2.2、epol…...
AI赋能服装零售:商品计划智能化,化危机为转机
在服装零售这片竞争激烈的战场上,每一个细微的决策都可能成为品牌兴衰的关键。当市场波动、消费者口味变化、供应链挑战接踵而至时,许多品牌往往将危机归咎于外部环境。然而,真相往往更为深刻——“危机不是外部的,而是你的商品计…...
课程预告|卓翼飞思多旋翼无人机集群实验课程即将上线,互动赢好礼
《多旋翼无人飞行器控制系统开发》实验课程自推出以来,吸引了众多高校的关注。目前,该课程已在多所学校成功实施,并广受好评。 点击链接查看飞控课程详情:课程上新| 卓翼飞思《多旋翼无人飞行器控制系统开发》实验课程正式发布 …...
AWS Glue从GCP的bigquery导入数据到AWS Redshift数据仓库
准备工作 创建账号与服务账号:拥有Google Cloud账号,创建有BigQuery权限的服务账号;拥有AWS账号,创建有相关权限的IAM用户。创建资源:创建Amazon Redshift集群或Redshift Serverless工作区,创建用于存储数…...
zookeeper shell操作和zookeeper 典型应用(配置中心、集群选举服务、分布式锁)
文章目录 引言I zookeeper客户端命令查看子节点 ls创建子节点 create获取节点信息 get更新节点数据 set删除节点 delete\ rmrII 监听机制node1:设置监听node3:修改监听节点node1:得到监听反馈III zookeeper 典型应用分布式锁集群选举服务数据发布/订阅(配置中心)引言 zk 的…...
如何解决HTML和CSS相关的问题,什么情况下会导致元素被遮挡?
在开发过程中,HTML 和 CSS 中的元素遮挡问题通常是由于布局、定位、层级等因素导致的。在使用 Vue.js 时,这些问题依然常见,尤其是涉及到动态渲染、条件渲染和组件嵌套的场景。以下是一些常见的导致元素被遮挡的原因,并通过 Vue.j…...
Java(3)封装、继承、多态
1.封装 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。 要访问该类的代码和数据,必须通过严格的接口控制。 封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。 pu…...
【深度学习】多目标融合算法(二):底部共享多任务模型(Shared-Bottom Multi-task Model)
目录 一、引言 1.1 往期回顾 1.2 本期概要 二、Shared-Bottom Multi-task Model(SBMM) 2.1 技术原理 2.2 技术优缺点 2.3 业务代码实践 三、总结 一、引言 在朴素的深度学习ctr预估模型中(如DNN),通常以一个行…...
后端:Spring(IOC、AOP)
文章目录 1. Spring2. IOC 控制反转2-1. 通过配置文件定义Bean2-1-1. 通过set方法来注入Bean2-1-2. 通过构造方法来注入Bean2-1-3. 自动装配2-1-4. 集合注入2-1-5. 数据源对象管理(第三方Bean)2-1-6. 在xml配置文件中加载properties文件的数据(context命名空间)2-1-7. 加载容器…...
基于SpringBoot的诊所管理系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...